diff --git a/.arclint b/.arclint new file mode 100644 index 000000000..6c5a03cd2 --- /dev/null +++ b/.arclint @@ -0,0 +1,8 @@ +{ + "linters": { + "cppcheck": { + "type": "cppcheck", + "include": ["(\\.cpp$)", "(\\.hpp$)"] + } + } +} diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a2b34d66..295694a8c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -86,6 +86,7 @@ set(fmt_source_dir ${libs_dir}/fmt) set(fmt_static_lib ${fmt_source_dir}/fmt/libfmt.a) # yaml-cpp set(yaml_source_dir ${libs_dir}/yaml-cpp) +set(yaml_include_dir ${yaml_source_dir}/include) set(yaml_static_lib ${yaml_source_dir}/libyaml-cpp.a) # Catch (C++ Automated Test Cases in Headers) set(catch_source_dir "${libs_dir}/Catch") @@ -137,10 +138,29 @@ endforeach() include(copy_includes) -# add all cpp file recursive into sourceFiles varibale -# FILE(GLOB_RECURSE sourceFiles ${src_dir}/*.cpp) -# print list of source files -# MESSAGE(STATUS "All source files are: ${sourceFiles}") +# linter setup (clang-tidy) +# all source files for linting +FILE(GLOB_RECURSE LINTER_SRC_FILES + ${src_dir}/*.cpp + ${CMAKE_SOURCE_DIR}/tests/.cpp + ${CMAKE_SOURCE_DIR}/poc/.cpp +) +MESSAGE(STATUS "All cpp files for linting are: ${LINTER_SRC_FILES}") + +# linter target clang-tidy +find_program(CLANG_TIDY "clang-tidy") +if(CLANG_TIDY) + add_custom_target( + clang-tidy + COMMAND /usr/bin/clang-tidy + ${LINTER_SRC_FILES} + -config='' + -- + -std=c++1y + -I${CMAKE_SOURCE_DIR}/include -I${fmt_source_dir} -I${yaml_include_dir} + ) +endif() +# linter setup # debug flags if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") @@ -244,7 +264,7 @@ include_directories(${CMAKE_SOURCE_DIR}/include) include_directories(${src_dir}) include_directories(${build_include_dir}) include_directories(${fmt_source_dir}) -include_directories(${yaml_source_dir}/include) +include_directories(${yaml_include_dir}) include_directories(${http_parser_source_dir}) include_directories(${lexertl_dir}) include_directories(${libuv_source_dir}/include) diff --git a/src/examples/.gitignore b/benchmark/.gitignore similarity index 100% rename from src/examples/.gitignore rename to benchmark/.gitignore diff --git a/src/benchmark/allocator.cpp b/benchmark/allocator.cpp similarity index 100% rename from src/benchmark/allocator.cpp rename to benchmark/allocator.cpp diff --git a/config/memgraph.yaml b/config/memgraph.yaml index 45e503188..1d9e4af54 100644 --- a/config/memgraph.yaml +++ b/config/memgraph.yaml @@ -9,7 +9,7 @@ compile_cpu_path: "./compiled/cpu/" # path to the template (cpp) for codes generation -template_cpu_cpp_path: "./template/template_code_cpu.cpp" +template_cpu_cpp_path: "./template/template_code_cpu_cpp" # path to the template (hpp) for codes generation template_cpu_hpp_path: "./template/template_code_cpu.hpp" diff --git a/example/.gitignore b/example/.gitignore new file mode 100644 index 000000000..f47cb2045 --- /dev/null +++ b/example/.gitignore @@ -0,0 +1 @@ +*.out diff --git a/src/examples/binomial.cpp b/example/binomial.cpp similarity index 100% rename from src/examples/binomial.cpp rename to example/binomial.cpp diff --git a/src/examples/client.cpp b/example/client.cpp similarity index 100% rename from src/examples/client.cpp rename to example/client.cpp diff --git a/src/examples/endinan.cpp b/example/endinan.cpp similarity index 100% rename from src/examples/endinan.cpp rename to example/endinan.cpp diff --git a/src/examples/exceptions.cpp b/example/exceptions.cpp similarity index 100% rename from src/examples/exceptions.cpp rename to example/exceptions.cpp diff --git a/src/examples/futex.cpp b/example/futex.cpp similarity index 100% rename from src/examples/futex.cpp rename to example/futex.cpp diff --git a/src/examples/hazard_ptrs.cpp b/example/hazard_ptrs.cpp similarity index 100% rename from src/examples/hazard_ptrs.cpp rename to example/hazard_ptrs.cpp diff --git a/src/examples/id.cpp b/example/id.cpp similarity index 100% rename from src/examples/id.cpp rename to example/id.cpp diff --git a/src/examples/index.cpp b/example/index.cpp similarity index 100% rename from src/examples/index.cpp rename to example/index.cpp diff --git a/src/examples/log.cpp b/example/log.cpp similarity index 100% rename from src/examples/log.cpp rename to example/log.cpp diff --git a/src/examples/proptest.cpp b/example/proptest.cpp similarity index 100% rename from src/examples/proptest.cpp rename to example/proptest.cpp diff --git a/src/examples/skiplist.cpp b/example/skiplist.cpp similarity index 100% rename from src/examples/skiplist.cpp rename to example/skiplist.cpp diff --git a/src/examples/skiplist_sentinel.cpp b/example/skiplist_sentinel.cpp similarity index 100% rename from src/examples/skiplist_sentinel.cpp rename to example/skiplist_sentinel.cpp diff --git a/src/examples/skiplistset.cpp b/example/skiplistset.cpp similarity index 100% rename from src/examples/skiplistset.cpp rename to example/skiplistset.cpp diff --git a/src/examples/strcmp.cpp b/example/strcmp.cpp similarity index 100% rename from src/examples/strcmp.cpp rename to example/strcmp.cpp diff --git a/src/examples/terminate_handler.cpp b/example/terminate_handler.cpp similarity index 100% rename from src/examples/terminate_handler.cpp rename to example/terminate_handler.cpp diff --git a/src/examples/timestamp.cpp b/example/timestamp.cpp old mode 100755 new mode 100644 similarity index 100% rename from src/examples/timestamp.cpp rename to example/timestamp.cpp diff --git a/src/examples/version_list.cpp b/example/version_list.cpp similarity index 100% rename from src/examples/version_list.cpp rename to example/version_list.cpp diff --git a/src/examples/xorshift.cpp b/example/xorshift.cpp similarity index 97% rename from src/examples/xorshift.cpp rename to example/xorshift.cpp index e52ab471e..351ff6d1b 100644 --- a/src/examples/xorshift.cpp +++ b/example/xorshift.cpp @@ -5,6 +5,7 @@ #include <array> #include <atomic> #include <thread> +#include <cassert> #include <sys/ioctl.h> #include <unistd.h> @@ -47,6 +48,7 @@ int main(void) auto max = std::accumulate(buckets.begin(), buckets.end(), 0u, [](auto& acc, auto& x) { return std::max(acc, x.load()); }); + assert(max != 0u); std::cout << std::fixed; diff --git a/src/data_structures/kdtree/build.hpp b/include/data_structures/kdtree/build.hpp similarity index 100% rename from src/data_structures/kdtree/build.hpp rename to include/data_structures/kdtree/build.hpp diff --git a/src/data_structures/kdtree/kdnode.hpp b/include/data_structures/kdtree/kdnode.hpp similarity index 100% rename from src/data_structures/kdtree/kdnode.hpp rename to include/data_structures/kdtree/kdnode.hpp diff --git a/src/data_structures/kdtree/kdtree.hpp b/include/data_structures/kdtree/kdtree.hpp similarity index 100% rename from src/data_structures/kdtree/kdtree.hpp rename to include/data_structures/kdtree/kdtree.hpp diff --git a/src/data_structures/kdtree/math.hpp b/include/data_structures/kdtree/math.hpp similarity index 100% rename from src/data_structures/kdtree/math.hpp rename to include/data_structures/kdtree/math.hpp diff --git a/src/data_structures/kdtree/nns.hpp b/include/data_structures/kdtree/nns.hpp similarity index 100% rename from src/data_structures/kdtree/nns.hpp rename to include/data_structures/kdtree/nns.hpp diff --git a/src/data_structures/kdtree/point.hpp b/include/data_structures/kdtree/point.hpp similarity index 100% rename from src/data_structures/kdtree/point.hpp rename to include/data_structures/kdtree/point.hpp diff --git a/src/data_structures/linked_list.hpp b/include/data_structures/linked_list.hpp similarity index 100% rename from src/data_structures/linked_list.hpp rename to include/data_structures/linked_list.hpp diff --git a/src/data_structures/list/lockfree_list.hpp b/include/data_structures/list/lockfree_list.hpp similarity index 100% rename from src/data_structures/list/lockfree_list.hpp rename to include/data_structures/list/lockfree_list.hpp diff --git a/src/data_structures/queue/bounded_spsc_queue.hpp b/include/data_structures/queue/bounded_spsc_queue.hpp similarity index 100% rename from src/data_structures/queue/bounded_spsc_queue.hpp rename to include/data_structures/queue/bounded_spsc_queue.hpp diff --git a/src/data_structures/queue/mpsc_queue.hpp b/include/data_structures/queue/mpsc_queue.hpp similarity index 100% rename from src/data_structures/queue/mpsc_queue.hpp rename to include/data_structures/queue/mpsc_queue.hpp diff --git a/src/data_structures/queue/slqueue.hpp b/include/data_structures/queue/slqueue.hpp similarity index 100% rename from src/data_structures/queue/slqueue.hpp rename to include/data_structures/queue/slqueue.hpp diff --git a/src/data_structures/slrbtree.hpp b/include/data_structures/slrbtree.hpp similarity index 100% rename from src/data_structures/slrbtree.hpp rename to include/data_structures/slrbtree.hpp diff --git a/src/data_structures/slstack.hpp b/include/data_structures/slstack.hpp similarity index 100% rename from src/data_structures/slstack.hpp rename to include/data_structures/slstack.hpp diff --git a/src/data_structures/stack/array_stack.hpp b/include/data_structures/stack/array_stack.hpp similarity index 100% rename from src/data_structures/stack/array_stack.hpp rename to include/data_structures/stack/array_stack.hpp diff --git a/src/data_structures/static_array.hpp b/include/data_structures/static_array.hpp similarity index 100% rename from src/data_structures/static_array.hpp rename to include/data_structures/static_array.hpp diff --git a/src/data_structures/union_find/union_find.hpp b/include/data_structures/union_find/union_find.hpp similarity index 100% rename from src/data_structures/union_find/union_find.hpp rename to include/data_structures/union_find/union_find.hpp diff --git a/src/memory/deferred_recycler.hpp b/include/memory/deferred_recycler.hpp similarity index 100% rename from src/memory/deferred_recycler.hpp rename to include/memory/deferred_recycler.hpp diff --git a/src/memory/hp.hpp b/include/memory/hp.hpp similarity index 100% rename from src/memory/hp.hpp rename to include/memory/hp.hpp diff --git a/src/memory/literals.hpp b/include/memory/literals.hpp similarity index 100% rename from src/memory/literals.hpp rename to include/memory/literals.hpp diff --git a/src/memory/memory.hpp b/include/memory/memory.hpp similarity index 100% rename from src/memory/memory.hpp rename to include/memory/memory.hpp diff --git a/src/memory/recycler.hpp b/include/memory/recycler.hpp similarity index 100% rename from src/memory/recycler.hpp rename to include/memory/recycler.hpp diff --git a/src/communication/bolt/v1/transport/bolt_decoder.cpp b/src/communication/bolt/v1/transport/bolt_decoder.cpp index 96248a8fc..973ce5989 100644 --- a/src/communication/bolt/v1/transport/bolt_decoder.cpp +++ b/src/communication/bolt/v1/transport/bolt_decoder.cpp @@ -90,7 +90,7 @@ std::string BoltDecoder::read_string() size = marker & 0x0F; } // if the marker is 0xD0, size is an 8-bit unsigned integer - if (marker == pack::String8) { + else if (marker == pack::String8) { size = read_byte(); } // if the marker is 0xD1, size is a 16-bit big-endian unsigned integer diff --git a/src/debug/log.hpp b/src/debug/log.hpp deleted file mode 100644 index 23094a46d..000000000 --- a/src/debug/log.hpp +++ /dev/null @@ -1,131 +0,0 @@ -#pragma once - -#include <sstream> -#include <iostream> -#include <thread> -#include <atomic> -#include <array> - -#include "data_structures/queue/mpsc_queue.hpp" -#include "utils/bash_colors.hpp" - -class Log -{ -public: - enum class Level : std::uint_fast8_t { Debug, Info, Warn, Error }; - - struct Message - { - std::chrono::system_clock::time_point time; - Level level; - std::string text; - std::string file; - std::string function; - size_t line; - - friend std::ostream& - operator<<(std::ostream& stream, const Message& message) - { - using namespace std::chrono; - - auto t = system_clock::to_time_t(message.time); - auto time_string = std::string(std::ctime(&t)); - - return stream << bash_color::green - << "[" << to_string(message.level) << "] " << bash_color::end - << message.text; - /* << bash_color::yellow << " on " << bash_color::end */ - /* << time_string.substr(0, time_string.size() - 1) */ - /* << bash_color::yellow << " in file " << bash_color::end */ - /* << message.file */ - /* << bash_color::yellow << " in function " << bash_color::end */ - /* << message.function */ - /* << bash_color::yellow << " at line " << bash_color::end */ - /* << message.line; */ - } - }; - - static std::array<std::string, 4> level_strings; - - static std::string to_string(Log::Level level) - { - return level_strings[static_cast<std::size_t>(level)]; - } - - Log() : alive(true), worker([this]() { work(); }) {} - - ~Log() - { - alive.store(false, std::memory_order_seq_cst); - worker.join(); - } - - static Log& instance() - { - static Log log; - return log; - } - -public: - Log(Log&) = delete; - Log(Log&&) = delete; - - static void log(Level level, const std::string& text, - const char* file, const char* function, size_t line) - { - using namespace std::chrono; - - auto& log = Log::instance(); - - log.messages.push(std::unique_ptr<Message>(new Message { - system_clock::now(), level, text, file, function, line - })); - } - -private: - lockfree::MpscQueue<Message> messages; - std::atomic<bool> alive; - std::thread worker; - - void work() - { - using namespace std::chrono_literals; - - while(true) - { - auto message = messages.pop(); - - if(message != nullptr) - { - std::cerr << *message << std::endl; - continue; - } - - if(!alive) - return; - - std::this_thread::sleep_for(10ms); - } - } -}; - -std::array<std::string, 4> Log::level_strings {{ - "DEBUG", "INFO", "WARN", "ERROR" -}}; - -#define LOG(_LEVEL_, _MESSAGE_) \ - Log::log( \ - _LEVEL_, \ - static_cast<std::ostringstream&>( \ - std::ostringstream().flush() << _MESSAGE_ \ - ).str(), \ - __FILE__, \ - __PRETTY_FUNCTION__, \ - __LINE__ \ - ); - -#ifdef NDEBUG -# define LOG_DEBUG(_) do {} while(0); -#else -# define LOG_DEBUG(_MESSAGE_) LOG(Log::Level::Debug, _MESSAGE_) -#endif diff --git a/src/demo/.gitignore b/src/demo/.gitignore deleted file mode 100644 index af8b9686e..000000000 --- a/src/demo/.gitignore +++ /dev/null @@ -1 +0,0 @@ -ve/ diff --git a/src/demo/.jshintrc b/src/demo/.jshintrc deleted file mode 100644 index 5eb122474..000000000 --- a/src/demo/.jshintrc +++ /dev/null @@ -1,8 +0,0 @@ -{ - "esnext": true, - "browser": true, - "globals": { - "sigma": true, - "console": true - } -} diff --git a/src/demo/__init__.py b/src/demo/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/demo/config/__init__.py b/src/demo/config/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/demo/config/config.py b/src/demo/config/config.py deleted file mode 100644 index c8ec8c72a..000000000 --- a/src/demo/config/config.py +++ /dev/null @@ -1,15 +0,0 @@ -# -*- coding: utf-8 -*- - -import json -from util import get_env, set_modul_attrs - -host = "0.0.0.0" - -port = 5000 - -log_level = 'INFO' - -try: - set_modul_attrs(__name__, json.loads(get_env('CONFIG'))) -except: - pass diff --git a/src/demo/demo_server.docker b/src/demo/demo_server.docker deleted file mode 100644 index 85646ad90..000000000 --- a/src/demo/demo_server.docker +++ /dev/null @@ -1,20 +0,0 @@ -FROM ubuntu:14.04 - -RUN apt-get update -RUN apt-get install -y python3.4 python3.4-dev python3-pip python3-setuptools -# RUN rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* - -RUN pip3 install flask - -COPY simulation /app/simulation -COPY demo_server_init.py /app/demo_server_init.py - -WORKDIR /app - -ENV MEMGRAPH_DEMO prod - -# uwsgi --http-socket 0.0.0.0:8080 --module demo_server_init:app \ -# --master --enable-threads -EXPOSE 8080 - -CMD ["python3", "demo_server_init.py"] diff --git a/src/demo/demo_server_init.py b/src/demo/demo_server_init.py deleted file mode 100644 index c13b60138..000000000 --- a/src/demo/demo_server_init.py +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -''' -The demo server init script. Environment could be configured -via the MEMGRAPH_DEMO environtment variable. Available environments -are: debug, prod. -''' - -import logging - -from util import get_env -from simulation.web_server import SimulationWebServer - -environment = get_env('MEMGRAPH_DEMO', 'debug') -wsgi = get_env('MEMGRAPH_DEMO_WSGI', 'werkzeug') - - -def _init(): - ''' - Initialzies logging level and server. - ''' - if environment == 'prod': - logging.basicConfig(level=logging.WARNING) - elif environment == 'test': - logging.basicConfig(level=logging.INFO) - else: - logging.basicConfig(level=logging.DEBUG) - - return SimulationWebServer().server - - -app = _init() - - -if __name__ == '__main__': - if wsgi == 'gevent': - from gevent.wsgi import WSGIServer - http_server = WSGIServer(('', 8080), app) - http_server.serve_forever() - else: - app.run(host="0.0.0.0", port=8080) diff --git a/src/demo/memgraph_server.docker b/src/demo/memgraph_server.docker deleted file mode 100644 index f4614ab62..000000000 --- a/src/demo/memgraph_server.docker +++ /dev/null @@ -1,10 +0,0 @@ -FROM ubuntu:16.04 - -RUN apt-get update -RUN apt-get install -y git - -RUN mkdir /app -WORKDIR /app -RUN git clone --recursive https://${MEMGRAPH_PULL_USER}:${MEMGRAPH_PULL_PASS}@phabricator.tomicevic.com/diffusion/MG/memgraph.git - -CMD ["/bin/bash"] diff --git a/src/demo/requirements.txt b/src/demo/requirements.txt deleted file mode 100644 index c878e3ffa..000000000 --- a/src/demo/requirements.txt +++ /dev/null @@ -1,19 +0,0 @@ -Cython==0.23.4 -Flask==0.10.1 -Jinja2==2.8 -MarkupSafe==0.23 -Werkzeug==0.11.4 -decorator==4.0.9 -gevent==1.1rc5 -greenlet==0.4.9 -ipython==4.1.1 -ipython-genutils==0.1.0 -itsdangerous==0.24 -path.py==8.1.2 -pexpect==4.0.1 -pickleshare==0.6 -ptyprocess==0.5.1 -requests==2.9.1 -simplegeneric==0.8.1 -traitlets==4.1.0 -uWSGI==2.0.12 diff --git a/src/demo/run_memgraph_server b/src/demo/run_memgraph_server deleted file mode 100755 index 61635632d..000000000 --- a/src/demo/run_memgraph_server +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -docker stop memgraph_demo -docker rm memgraph_demo -docker run -it --rm memgraph_demo diff --git a/src/demo/run_neo4j_server b/src/demo/run_neo4j_server deleted file mode 100755 index 37fce1bdf..000000000 --- a/src/demo/run_neo4j_server +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -docker stop neo4j_server -docker rm neo4j_server -docker run -d --name neo4j_server --net=host -p 7474:7474 neo4j diff --git a/src/demo/service_init.py b/src/demo/service_init.py deleted file mode 100644 index 56389c275..000000000 --- a/src/demo/service_init.py +++ /dev/null @@ -1,7 +0,0 @@ -# -*- coding: UTF-8 -*- - -# TODO init object by module name - -# something like -# module_name, class_name = module_class_string.rsplit(".", 1) -# return getattr(importlib.import_module(module_name), class_name)() diff --git a/src/demo/simulation/__init__.py b/src/demo/simulation/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/demo/simulation/epoch_result.py b/src/demo/simulation/epoch_result.py deleted file mode 100644 index 437b81846..000000000 --- a/src/demo/simulation/epoch_result.py +++ /dev/null @@ -1,26 +0,0 @@ -# -*- coding: utf-8 -*- - - -class SimulationEpochResult(object): - ''' - Encapsulates single epoch result. - ''' - - def __init__(self, per_query, for_all): - ''' - Sets per_query and for_all results. - - :param per_query: list of SimulationGroupResult objects - :param for_all: float, queries per second - ''' - self.per_query = per_query - self.for_all = for_all - - def json_data(self): - ''' - :returns: dict, epoch results - ''' - return { - "per_query": [item.json_data() for item in self.per_query], - "for_all": self.for_all - } diff --git a/src/demo/simulation/executor.py b/src/demo/simulation/executor.py deleted file mode 100644 index 46a97a98c..000000000 --- a/src/demo/simulation/executor.py +++ /dev/null @@ -1,150 +0,0 @@ -# -*- coding: utf-8 -*- - -import os -import json -import time -import logging -import itertools -import http -from concurrent.futures import ProcessPoolExecutor - -from .substitutor import substitute -from .epoch_result import SimulationEpochResult -from .group_result import SimulationGroupResult -from .iteration_result import SimulationIterationResult - -log = logging.getLogger(__name__) - - -def calculate_qps(results, delta_t=None): - ''' - Calculates queris per second for the results list. The main idea - is to scale up results to the result with the biggest execution time. - - Example: - Let say that 2 workers execute the same query. First worker - executes 100 queries in 1s, second worker executes 10 queries in 10s. - In that case first query result has to be scaled up. - Here we are goint to make aproximation, if first worker - execution time was 10s, it would execute 1000 queries. - So, the total speed is (1000q + 10q) / 10s = 101 qps. In that case - 101 would be returned from this function. - - :param results: list of SimulationIterationResult objects - :returns: queries per second result calculated on the input list - ''' - min_start_time = min([result.start_time for result in results]) - max_end_time = max([result.end_time for result in results]) - delta_t = max_end_time - min_start_time - qps = sum([result.count for result in results]) / delta_t - return qps - - -class SimulationExecutor(object): - ''' - The main executor object. Every period the instance of this class - will execute all queries, collect the results and calculate speed of - queries execution. - ''' - - def setup(self, params): - ''' - Setup params and initialize the workers pool. - - :param params: SimulationParams object - ''' - self.params = params - self.pool = ProcessPoolExecutor - return self - - def send(self, connection, query): - ''' - Sends the query to the graph database. - - :param connection: http.client.HTTPConnection - :param query: str, query string - ''' - body = json.dumps({'statements': [{'statement': substitute(query)}]}) - headers = { - 'Authorization': self.params.authorization, - 'Content-Type': 'application/json' - } - connection.request('POST', '/db/data/transaction/commit', - body=body, headers=headers) - response = connection.getresponse() - log.debug('New response: %s' % response.read()) - - def iteration(self, task): - ''' - Executes the task. Task encapsulates the informations about query. - The task is smallest piece of work and this method will try to execute - queries (one query, more times) from the task as fastest as possible. - Execution time of this method is constrained with the period_time time. - - :param task: instance of SimulationTask class. - :returns: SimulationIterationResult - ''' - count = 0 - delta_t = 0 - - log.debug("New worker with PID: %s" % os.getpid()) - - connection = http.client.HTTPConnection( - self.params.host, self.params.port) - connection.connect() - - start_time = time.time() - - for i in range(self.params.queries_per_period): - - # send the query on execution - self.send(connection, task.query) - - # calculate delta time - end_time = time.time() - delta_t = end_time - start_time - - count = count + 1 - - if delta_t > self.params.period_time: - break - - connection.close() - - return SimulationIterationResult(task.id, count, start_time, end_time) - - def epoch(self): - ''' - Single simulation epoc. All workers are going to execute - their queries in the period that is period_time seconds length. - ''' - log.debug('epoch') - - max_workers = self.params.workers_per_query * len(self.params.tasks) - - with self.pool(max_workers=max_workers) as executor: - - log.debug('pool iter') - - # execute all tasks - start_time = time.time() - futures = [executor.submit(self.iteration, task) - for task in self.params.tasks - for i in range(self.params.workers_per_query)] - results = [future.result() for future in futures] - end_time = time.time() - epoch_time = end_time - start_time - log.info("Total epoch time: %s" % epoch_time) - - # per query calculation - grouped = itertools.groupby(results, lambda x: x.id) - per_query = [SimulationGroupResult(id, calculate_qps(list(tasks))) - for id, tasks in grouped] - - # for all calculation - for_all = calculate_qps(results) - - log.info('Queries per period: %s' % sum([r.count - for r in results])) - - return SimulationEpochResult(per_query, for_all) diff --git a/src/demo/simulation/group_result.py b/src/demo/simulation/group_result.py deleted file mode 100644 index 8c34eab0d..000000000 --- a/src/demo/simulation/group_result.py +++ /dev/null @@ -1,25 +0,0 @@ -# -*- coding: utf-8 -*- - - -class SimulationGroupResult(object): - ''' - Encapsulates query per seconds information for qroup of workers - (all workers that execute the same query). - ''' - - def __init__(self, id, queries_per_second): - ''' - :param id: str, query id - :param queries_per_second: float, queries per second - ''' - self.id = id - self.queries_per_second = queries_per_second - - def json_data(self): - ''' - :returns: dict, {query_id(str):queries_per_second(float)} - ''' - return { - 'id': self.id, - 'queries_per_second': self.queries_per_second - } diff --git a/src/demo/simulation/iteration_result.py b/src/demo/simulation/iteration_result.py deleted file mode 100644 index b7c024e72..000000000 --- a/src/demo/simulation/iteration_result.py +++ /dev/null @@ -1,29 +0,0 @@ -# -*- coding: utf-8 -*- - - -class SimulationIterationResult(object): - ''' - Encapsulates single worker result. - ''' - - def __init__(self, id, count, start_time, end_time): - ''' - :param id: str, query id - :param count: int, number of the query exection - :param delta_t: time of execution - ''' - self.id = id - self.count = count - self.start_time = start_time - self.end_time = end_time - self.delta_t = end_time - start_time - self.queries_per_second = self.count / self.delta_t - - def json_data(self): - ''' - :returns: dict {query_id(str):queries_per_second(float)} - ''' - return { - "id": self.id, - "queries_per_second": self.queries_per_second - } diff --git a/src/demo/simulation/params.py b/src/demo/simulation/params.py deleted file mode 100644 index 7745400e1..000000000 --- a/src/demo/simulation/params.py +++ /dev/null @@ -1,162 +0,0 @@ -# -*- coding: utf-8 -*- - -import base64 -import logging - -log = logging.getLogger(__name__) - - -class SimulationParams(object): - ''' - Encapsulates the simulation params. - ''' - - def __init__(self): - ''' - Setup default params values. - ''' - self.protocol = 'http' - self.host = 'localhost' - self.port = 7474 - self.username = '' - self.password = '' - - self.period_time = 0.5 - self.workers_per_query = 1 - self.queries_per_second = 15000 - self.recalculate_qpp() - - self.tasks = [] - - def json_data(self): - ''' - :returns: dict with all param values - ''' - return { - "protocol": self.protocol, - "host": self.host, - "port": self.port, - "username": self.username, - "password": self.password, - "period_time": self.period_time, - "workers_per_query": self.workers_per_query, - "queries_per_period": self.queries_per_period, - "queries_per_second": self.queries_per_second - } - - # protocol - @property - def protocol(self): - return self._protocol - - @protocol.setter - def protocol(self, value): - self._protocol = value - - # host - @property - def host(self): - return self._host - - @host.setter - def host(self, value): - self._host = value - - # port - @property - def port(self): - return self._port - - @port.setter - def port(self, value): - self._port = value - - # username - @property - def username(self): - return self._username - - @username.setter - def username(self, value): - self._username = value - log.info("Username is now: %s" % self._username) - self.http_basic() - - # password - @property - def password(self): - return self._password - - @password.setter - def password(self, value): - self._password = value - log.info("Password is now: %s" % self._password) - self.http_basic() - - def http_basic(self): - ''' - Recalculates http authorization header. - ''' - try: - encoded = base64.b64encode( - str.encode(self.username + ":" + self.password)) - self.authorization = "Basic " + encoded.decode() - log.info("Authorization is now: %s" % self.authorization) - except AttributeError: - log.debug("Username or password isn't defined.") - except Exception as e: - log.exception(e) - - # authorization - @property - def authorization(self): - return self._authorization - - @authorization.setter - def authorization(self, value): - self._authorization = value - - # workers per query - @property - def workers_per_query(self): - return self._workers_per_query - - @workers_per_query.setter - def workers_per_query(self, value): - self._workers_per_query = value - - # queries per second - @property - def queries_per_second(self): - return self._queries_per_second - - @queries_per_second.setter - def queries_per_second(self, value): - self._queries_per_second = value - self.recalculate_qpp() - - def recalculate_qpp(self): - try: - self.queries_per_period = \ - int(self.queries_per_second * self.period_time) - except: - pass - - # queries per period - @property - def queries_per_period(self): - return self._queries_per_period - - @queries_per_period.setter - def queries_per_period(self, value): - self._queries_per_period = value - - # period time - @property - def period_time(self): - return self._period_time - - @period_time.setter - def period_time(self, value): - self._period_time = value - self.recalculate_qpp() diff --git a/src/demo/simulation/substitutor.py b/src/demo/simulation/substitutor.py deleted file mode 100644 index 7125fb0a5..000000000 --- a/src/demo/simulation/substitutor.py +++ /dev/null @@ -1,77 +0,0 @@ -# -*- coding: utf-8 -*- - -import sys -import random -import string - - -char_options = string.ascii_lowercase + string.digits - - -def random_integer(start=0, end=sys.maxsize): - ''' - :returns: random integer between start and end - ''' - return random.randint(start, end) - - -def random_float(start=0, end=1): - ''' - :returns: random float between start and end (uniform distribution) - ''' - return random.uniform(start, end) - - -def random_bool(): - ''' - :returns: random bool value - ''' - return bool(random.getrandbits(1)) - - -def random_string(size=5): - ''' - :param size: int, string size - - :returns: random string of specific size build from ascii_lowercase chars - and digits - ''' - return ''.join([random.choice(char_options) - for _ in range(size)]) - - -placeholders = { - '#': random_integer, - '@': random_float, - '*': random_bool, - '^': random_string -} - - -def substitute(text='', placeholders=placeholders): - ''' - Substitutes chars in text with values generated from functions placed - in placeholders dict. - - :param text: str, substitutable text - :param placeholders: dict, key is char that will be substituted, value - is function that is going to be used to generate - a new value - ''' - return ''.join((c if c not in placeholders else str(placeholders[c]()) - for c in iter(text))) - - -if __name__ == '__main__': - - def test_1(): - print([f() for f in [random_integer, random_float, - random_bool, random_string]]) - - def test_2(): - return substitute('int # float @ bool * string ^') - - def test_3(): - print(test_2()) - - test_3() diff --git a/src/demo/simulation/task.py b/src/demo/simulation/task.py deleted file mode 100644 index 0c8f267c7..000000000 --- a/src/demo/simulation/task.py +++ /dev/null @@ -1,24 +0,0 @@ -# -*- coding: utf-8 -*- - - -class SimulationTask(object): - ''' - Encapsulates query data. - ''' - - def __init__(self, id, query): - ''' - :param id: query id - :param query: str, query string - ''' - self.id = id - self.query = query - - def json_data(self): - ''' - :returns: dict with all elements - ''' - return { - "id": self.id, - "query": self.query - } diff --git a/src/demo/simulation/web_server.py b/src/demo/simulation/web_server.py deleted file mode 100644 index a2b7139cd..000000000 --- a/src/demo/simulation/web_server.py +++ /dev/null @@ -1,163 +0,0 @@ -# -*- coding: utf-8 -*- - -import json -import logging -import threading -from flask import Flask, request, jsonify - -from .executor import SimulationExecutor -from .params import SimulationParams -from .task import SimulationTask - -log = logging.getLogger(__name__) - - -class SimulationWebServer(object): - ''' - Memgraph demo fontend server. For now it wraps the flask server. - ''' - - def __init__(self): - ''' - Instantiates the flask web server. - ''' - self.is_simulation_running = False - self.simulation_stats = None - self.simulation_params = SimulationParams() - self.simulation_executor = SimulationExecutor() - self.server = Flask(__name__) - self.setup_routes() - self.server.before_first_request(self.before_first_request) - - def setup_routes(self): - ''' - Setup all routes. - ''' - self.add_route('/ping', self.ping, 'GET') - self.add_route('/', self.index, 'GET') - self.add_route('/<path:path>', self.static, 'GET') - self.add_route('/tasks', self.tasks_get, 'GET') - self.add_route('/tasks', self.tasks_set, 'POST') - self.add_route('/start', self.start, 'POST') - self.add_route('/stop', self.stop, 'POST') - self.add_route('/stats', self.stats, 'GET') - self.add_route('/params', self.params_get, 'GET') - self.add_route('/params', self.params_set, 'POST') - - def before_first_request(self): - ''' - Initializes simulation executor before first request. - ''' - log.info('before first request') - self.simulation_executor.setup(self.simulation_params) - - def add_route(self, route, code_method, http_method): - ''' - Registers URL rule - - :param route: str, route string - :param object_method: object method responsible for the - request handling - :param http_method: name of http method - ''' - self.server.add_url_rule(route, '%s_%s' % (route, http_method), - code_method, methods=[http_method]) - - def ping(self): - ''' - Ping endpoint. Returns 204 HTTP status code. - ''' - return ('', 204) - - def index(self): - ''' - Serves demo.html on the index path. - ''' - print('index') - return self.server.send_static_file('demo.html') - - def static(self, path): - ''' - Serves other static files. - ''' - return self.server.send_static_file(path) - - def tasks_get(self): - ''' - Retutns all defined tasks. - ''' - return json.dumps( - [task.json_data() for task in self.simulation_params.tasks] - ) - - def tasks_set(self): - ''' - Register tasks. Task is object that encapsulates single query data. - ''' - data = request.get_json()['data'] - - self.simulation_params.tasks = \ - [SimulationTask(item['id'], item['query']) - for item in data] - - return ('', 200) - - def run_simulation(self): - ''' - If flag is_simulation_running flag is up (True) the executor - epoch will be executed. Epochs will be executed until somebody - set is_simulation_running flag to Flase. - ''' - log.info('new simulation run') - - while self.is_simulation_running: - self.simulation_stats = self.simulation_executor.epoch() - - def start(self): - ''' - Starts new executor epoch in separate thread. - ''' - self.is_simulation_running = True - t = threading.Thread(target=self.run_simulation, daemon=True) - t.start() - return ('', 204) - - def stop(self): - ''' - On POST /stop, stops the executor. The is not immediately, first - the is_simulation_running flag is set to False value, and next - epoc of executor won't be executed. - ''' - self.is_simulation_running = False - return ('', 204) - - def stats(self): - ''' - Returns the simulation stats. Queries per second. - ''' - if not self.simulation_stats: - return ('', 204) - - return jsonify(self.simulation_stats.json_data()) - - def params_get(self): - ''' - Returns simulation parameters. - ''' - return jsonify(self.simulation_params.json_data()) - - def params_set(self): - ''' - Sets simulation parameters. - ''' - data = request.get_json() - - param_names = ['protocol', 'host', 'port', 'username', 'password', - 'period_time', 'queries_per_second', - 'workers_per_query'] - - for param in param_names: - if param in data: - setattr(self.simulation_params, param, data[param]) - - return self.params_get() diff --git a/src/demo/static/cypher/.gitattributes b/src/demo/static/cypher/.gitattributes deleted file mode 100644 index f8bdd60f4..000000000 --- a/src/demo/static/cypher/.gitattributes +++ /dev/null @@ -1,8 +0,0 @@ -*.txt text -*.js text -*.html text -*.md text -*.json text -*.yml text -*.css text -*.svg text diff --git a/src/demo/static/cypher/.gitignore b/src/demo/static/cypher/.gitignore deleted file mode 100644 index f91c241f2..000000000 --- a/src/demo/static/cypher/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -/node_modules -/npm-debug.log -/test*.html -.tern-* -*~ -*.swp -.idea -*.iml diff --git a/src/demo/static/cypher/.npmignore b/src/demo/static/cypher/.npmignore deleted file mode 100644 index 5ed053f89..000000000 --- a/src/demo/static/cypher/.npmignore +++ /dev/null @@ -1,10 +0,0 @@ -/node_modules -/demo -/doc -/test -/test*.html -/index.html -/mode/*/*test.js -/mode/*/*.html -/mode/index.html -.* diff --git a/src/demo/static/cypher/.travis.yml b/src/demo/static/cypher/.travis.yml deleted file mode 100644 index 52b8b8159..000000000 --- a/src/demo/static/cypher/.travis.yml +++ /dev/null @@ -1,4 +0,0 @@ -language: node_js -node_js: - - stable -sudo: false diff --git a/src/demo/static/cypher/codemirror.css b/src/demo/static/cypher/codemirror.css deleted file mode 100644 index ebfe4f697..000000000 --- a/src/demo/static/cypher/codemirror.css +++ /dev/null @@ -1,335 +0,0 @@ -/* BASICS */ - -.CodeMirror { - /* Set height, width, borders, and global font properties here */ - font-family: monospace; - height: 300px; - color: black; -} - -/* PADDING */ - -.CodeMirror-lines { - padding: 4px 0; /* Vertical padding around content */ -} -.CodeMirror pre { - padding: 0 4px; /* Horizontal padding of content */ -} - -.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { - background-color: white; /* The little square between H and V scrollbars */ -} - -/* GUTTER */ - -.CodeMirror-gutters { - border-right: 1px solid #ddd; - background-color: #f7f7f7; - white-space: nowrap; -} -.CodeMirror-linenumbers {} -.CodeMirror-linenumber { - padding: 0 3px 0 5px; - min-width: 20px; - text-align: right; - color: #999; - white-space: nowrap; -} - -.CodeMirror-guttermarker { color: black; } -.CodeMirror-guttermarker-subtle { color: #999; } - -/* CURSOR */ - -.CodeMirror-cursor { - border-left: 1px solid black; - border-right: none; - width: 0; -} -/* Shown when moving in bi-directional text */ -.CodeMirror div.CodeMirror-secondarycursor { - border-left: 1px solid silver; -} -.cm-fat-cursor .CodeMirror-cursor { - width: auto; - border: 0; - background: #7e7; -} -.cm-fat-cursor div.CodeMirror-cursors { - z-index: 1; -} - -.cm-animate-fat-cursor { - width: auto; - border: 0; - -webkit-animation: blink 1.06s steps(1) infinite; - -moz-animation: blink 1.06s steps(1) infinite; - animation: blink 1.06s steps(1) infinite; - background-color: #7e7; -} -@-moz-keyframes blink { - 0% {} - 50% { background-color: transparent; } - 100% {} -} -@-webkit-keyframes blink { - 0% {} - 50% { background-color: transparent; } - 100% {} -} -@keyframes blink { - 0% {} - 50% { background-color: transparent; } - 100% {} -} - -/* Can style cursor different in overwrite (non-insert) mode */ -.CodeMirror-overwrite .CodeMirror-cursor {} - -.cm-tab { display: inline-block; text-decoration: inherit; } - -.CodeMirror-ruler { - border-left: 1px solid #ccc; - position: absolute; -} - -/* DEFAULT THEME */ - -.cm-s-default .cm-header {color: blue;} -.cm-s-default .cm-quote {color: #090;} -.cm-negative {color: #d44;} -.cm-positive {color: #292;} -.cm-header, .cm-strong {font-weight: bold;} -.cm-em {font-style: italic;} -.cm-link {text-decoration: underline;} -.cm-strikethrough {text-decoration: line-through;} - -.cm-s-default .cm-keyword {color: #708;} -.cm-s-default .cm-atom {color: #219;} -.cm-s-default .cm-number {color: #164;} -.cm-s-default .cm-def {color: #00f;} -.cm-s-default .cm-variable, -.cm-s-default .cm-punctuation, -.cm-s-default .cm-property, -.cm-s-default .cm-operator {} -.cm-s-default .cm-variable-2 {color: #05a;} -.cm-s-default .cm-variable-3 {color: #085;} -.cm-s-default .cm-comment {color: #a50;} -.cm-s-default .cm-string {color: #a11;} -.cm-s-default .cm-string-2 {color: #f50;} -.cm-s-default .cm-meta {color: #555;} -.cm-s-default .cm-qualifier {color: #555;} -.cm-s-default .cm-builtin {color: #30a;} -.cm-s-default .cm-bracket {color: #997;} -.cm-s-default .cm-tag {color: #170;} -.cm-s-default .cm-attribute {color: #00c;} -.cm-s-default .cm-hr {color: #999;} -.cm-s-default .cm-link {color: #00c;} - -.cm-s-default .cm-error {color: #f00;} -.cm-invalidchar {color: #f00;} - -.CodeMirror-composing { border-bottom: 2px solid; } - -/* Default styles for common addons */ - -div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;} -div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} -.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); } -.CodeMirror-activeline-background {background: #e8f2ff;} - -/* STOP */ - -/* The rest of this file contains styles related to the mechanics of - the editor. You probably shouldn't touch them. */ - -.CodeMirror { - position: relative; - overflow: hidden; - background: white; -} - -.CodeMirror-scroll { - overflow: scroll !important; /* Things will break if this is overridden */ - /* 30px is the magic margin used to hide the element's real scrollbars */ - /* See overflow: hidden in .CodeMirror */ - margin-bottom: -30px; margin-right: -30px; - padding-bottom: 30px; - height: 100%; - outline: none; /* Prevent dragging from highlighting the element */ - position: relative; -} -.CodeMirror-sizer { - position: relative; - border-right: 30px solid transparent; -} - -/* The fake, visible scrollbars. Used to force redraw during scrolling - before actual scrolling happens, thus preventing shaking and - flickering artifacts. */ -.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { - position: absolute; - z-index: 6; - display: none; -} -.CodeMirror-vscrollbar { - right: 0; top: 0; - overflow-x: hidden; - overflow-y: scroll; -} -.CodeMirror-hscrollbar { - bottom: 0; left: 0; - overflow-y: hidden; - overflow-x: scroll; -} -.CodeMirror-scrollbar-filler { - right: 0; bottom: 0; -} -.CodeMirror-gutter-filler { - left: 0; bottom: 0; -} - -.CodeMirror-gutters { - position: absolute; left: 0; top: 0; - z-index: 3; -} -.CodeMirror-gutter { - white-space: normal; - height: 100%; - display: inline-block; - vertical-align: top; - margin-bottom: -30px; - /* Hack to make IE7 behave */ - *zoom:1; - *display:inline; -} -.CodeMirror-gutter-wrapper { - position: absolute; - z-index: 4; - background: none !important; - border: none !important; -} -.CodeMirror-gutter-background { - position: absolute; - top: 0; bottom: 0; - z-index: 4; -} -.CodeMirror-gutter-elt { - position: absolute; - cursor: default; - z-index: 4; -} -.CodeMirror-gutter-wrapper { - -webkit-user-select: none; - -moz-user-select: none; - user-select: none; -} - -.CodeMirror-lines { - cursor: text; - min-height: 1px; /* prevents collapsing before first draw */ -} -.CodeMirror pre { - /* Reset some styles that the rest of the page might have set */ - -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0; - border-width: 0; - background: transparent; - font-family: inherit; - font-size: inherit; - margin: 0; - white-space: pre; - word-wrap: normal; - line-height: inherit; - color: inherit; - z-index: 2; - position: relative; - overflow: visible; - -webkit-tap-highlight-color: transparent; -} -.CodeMirror-wrap pre { - word-wrap: break-word; - white-space: pre-wrap; - word-break: normal; -} - -.CodeMirror-linebackground { - position: absolute; - left: 0; right: 0; top: 0; bottom: 0; - z-index: 0; -} - -.CodeMirror-linewidget { - position: relative; - z-index: 2; - overflow: auto; -} - -.CodeMirror-widget {} - -.CodeMirror-code { - outline: none; -} - -/* Force content-box sizing for the elements where we expect it */ -.CodeMirror-scroll, -.CodeMirror-sizer, -.CodeMirror-gutter, -.CodeMirror-gutters, -.CodeMirror-linenumber { - -moz-box-sizing: content-box; - box-sizing: content-box; -} - -.CodeMirror-measure { - position: absolute; - width: 100%; - height: 0; - overflow: hidden; - visibility: hidden; -} - -.CodeMirror-cursor { position: absolute; } -.CodeMirror-measure pre { position: static; } - -div.CodeMirror-cursors { - visibility: hidden; - position: relative; - z-index: 3; -} -div.CodeMirror-dragcursors { - visibility: visible; -} - -.CodeMirror-focused div.CodeMirror-cursors { - visibility: visible; -} - -.CodeMirror-selected { background: #d9d9d9; } -.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; } -.CodeMirror-crosshair { cursor: crosshair; } -.CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; } -.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; } - -.cm-searching { - background: #ffa; - background: rgba(255, 255, 0, .4); -} - -/* IE7 hack to prevent it from returning funny offsetTops on the spans */ -.CodeMirror span { *vertical-align: text-bottom; } - -/* Used to force a border model for a node */ -.cm-force-border { padding-right: .1px; } - -@media print { - /* Hide the cursor when printing */ - .CodeMirror div.CodeMirror-cursors { - visibility: hidden; - } -} - -/* See issue #2901 */ -.cm-tab-wrap-hack:after { content: ''; } - -/* Help users use markselection to safely style text background */ -span.CodeMirror-selectedtext { background: none; } diff --git a/src/demo/static/cypher/codemirror.js b/src/demo/static/cypher/codemirror.js deleted file mode 100644 index e803211bc..000000000 --- a/src/demo/static/cypher/codemirror.js +++ /dev/null @@ -1,8892 +0,0 @@ -// CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: http://codemirror.net/LICENSE - -// This is CodeMirror (http://codemirror.net), a code editor -// implemented in JavaScript on top of the browser's DOM. -// -// You can find some technical background for some of the code below -// at http://marijnhaverbeke.nl/blog/#cm-internals . - -(function(mod) { - if (typeof exports == "object" && typeof module == "object") // CommonJS - module.exports = mod(); - else if (typeof define == "function" && define.amd) // AMD - return define([], mod); - else // Plain browser env - (this || window).CodeMirror = mod(); -})(function() { - "use strict"; - - // BROWSER SNIFFING - - // Kludges for bugs and behavior differences that can't be feature - // detected are enabled based on userAgent etc sniffing. - var userAgent = navigator.userAgent; - var platform = navigator.platform; - - var gecko = /gecko\/\d/i.test(userAgent); - var ie_upto10 = /MSIE \d/.test(userAgent); - var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(userAgent); - var ie = ie_upto10 || ie_11up; - var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : ie_11up[1]); - var webkit = /WebKit\//.test(userAgent); - var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(userAgent); - var chrome = /Chrome\//.test(userAgent); - var presto = /Opera\//.test(userAgent); - var safari = /Apple Computer/.test(navigator.vendor); - var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(userAgent); - var phantom = /PhantomJS/.test(userAgent); - - var ios = /AppleWebKit/.test(userAgent) && /Mobile\/\w+/.test(userAgent); - // This is woefully incomplete. Suggestions for alternative methods welcome. - var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent); - var mac = ios || /Mac/.test(platform); - var windows = /win/i.test(platform); - - var presto_version = presto && userAgent.match(/Version\/(\d*\.\d*)/); - if (presto_version) presto_version = Number(presto_version[1]); - if (presto_version && presto_version >= 15) { presto = false; webkit = true; } - // Some browsers use the wrong event properties to signal cmd/ctrl on OS X - var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11)); - var captureRightClick = gecko || (ie && ie_version >= 9); - - // Optimize some code when these features are not used. - var sawReadOnlySpans = false, sawCollapsedSpans = false; - - // EDITOR CONSTRUCTOR - - // A CodeMirror instance represents an editor. This is the object - // that user code is usually dealing with. - - function CodeMirror(place, options) { - if (!(this instanceof CodeMirror)) return new CodeMirror(place, options); - - this.options = options = options ? copyObj(options) : {}; - // Determine effective options based on given values and defaults. - copyObj(defaults, options, false); - setGuttersForLineNumbers(options); - - var doc = options.value; - if (typeof doc == "string") doc = new Doc(doc, options.mode, null, options.lineSeparator); - this.doc = doc; - - var input = new CodeMirror.inputStyles[options.inputStyle](this); - var display = this.display = new Display(place, doc, input); - display.wrapper.CodeMirror = this; - updateGutters(this); - themeChanged(this); - if (options.lineWrapping) - this.display.wrapper.className += " CodeMirror-wrap"; - if (options.autofocus && !mobile) display.input.focus(); - initScrollbars(this); - - this.state = { - keyMaps: [], // stores maps added by addKeyMap - overlays: [], // highlighting overlays, as added by addOverlay - modeGen: 0, // bumped when mode/overlay changes, used to invalidate highlighting info - overwrite: false, - delayingBlurEvent: false, - focused: false, - suppressEdits: false, // used to disable editing during key handlers when in readOnly mode - pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in input.poll - selectingText: false, - draggingText: false, - highlight: new Delayed(), // stores highlight worker timeout - keySeq: null, // Unfinished key sequence - specialChars: null - }; - - var cm = this; - - // Override magic textarea content restore that IE sometimes does - // on our hidden textarea on reload - if (ie && ie_version < 11) setTimeout(function() { cm.display.input.reset(true); }, 20); - - registerEventHandlers(this); - ensureGlobalHandlers(); - - startOperation(this); - this.curOp.forceUpdate = true; - attachDoc(this, doc); - - if ((options.autofocus && !mobile) || cm.hasFocus()) - setTimeout(bind(onFocus, this), 20); - else - onBlur(this); - - for (var opt in optionHandlers) if (optionHandlers.hasOwnProperty(opt)) - optionHandlers[opt](this, options[opt], Init); - maybeUpdateLineNumberWidth(this); - if (options.finishInit) options.finishInit(this); - for (var i = 0; i < initHooks.length; ++i) initHooks[i](this); - endOperation(this); - // Suppress optimizelegibility in Webkit, since it breaks text - // measuring on line wrapping boundaries. - if (webkit && options.lineWrapping && - getComputedStyle(display.lineDiv).textRendering == "optimizelegibility") - display.lineDiv.style.textRendering = "auto"; - } - - // DISPLAY CONSTRUCTOR - - // The display handles the DOM integration, both for input reading - // and content drawing. It holds references to DOM nodes and - // display-related state. - - function Display(place, doc, input) { - var d = this; - this.input = input; - - // Covers bottom-right square when both scrollbars are present. - d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler"); - d.scrollbarFiller.setAttribute("cm-not-content", "true"); - // Covers bottom of gutter when coverGutterNextToScrollbar is on - // and h scrollbar is present. - d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler"); - d.gutterFiller.setAttribute("cm-not-content", "true"); - // Will contain the actual code, positioned to cover the viewport. - d.lineDiv = elt("div", null, "CodeMirror-code"); - // Elements are added to these to represent selection and cursors. - d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1"); - d.cursorDiv = elt("div", null, "CodeMirror-cursors"); - // A visibility: hidden element used to find the size of things. - d.measure = elt("div", null, "CodeMirror-measure"); - // When lines outside of the viewport are measured, they are drawn in this. - d.lineMeasure = elt("div", null, "CodeMirror-measure"); - // Wraps everything that needs to exist inside the vertically-padded coordinate system - d.lineSpace = elt("div", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv], - null, "position: relative; outline: none"); - // Moved around its parent to cover visible view. - d.mover = elt("div", [elt("div", [d.lineSpace], "CodeMirror-lines")], null, "position: relative"); - // Set to the height of the document, allowing scrolling. - d.sizer = elt("div", [d.mover], "CodeMirror-sizer"); - d.sizerWidth = null; - // Behavior of elts with overflow: auto and padding is - // inconsistent across browsers. This is used to ensure the - // scrollable area is big enough. - d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerGap + "px; width: 1px;"); - // Will contain the gutters, if any. - d.gutters = elt("div", null, "CodeMirror-gutters"); - d.lineGutter = null; - // Actual scrollable element. - d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll"); - d.scroller.setAttribute("tabIndex", "-1"); - // The element in which the editor lives. - d.wrapper = elt("div", [d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror"); - - // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported) - if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; } - if (!webkit && !(gecko && mobile)) d.scroller.draggable = true; - - if (place) { - if (place.appendChild) place.appendChild(d.wrapper); - else place(d.wrapper); - } - - // Current rendered range (may be bigger than the view window). - d.viewFrom = d.viewTo = doc.first; - d.reportedViewFrom = d.reportedViewTo = doc.first; - // Information about the rendered lines. - d.view = []; - d.renderedView = null; - // Holds info about a single rendered line when it was rendered - // for measurement, while not in view. - d.externalMeasured = null; - // Empty space (in pixels) above the view - d.viewOffset = 0; - d.lastWrapHeight = d.lastWrapWidth = 0; - d.updateLineNumbers = null; - - d.nativeBarWidth = d.barHeight = d.barWidth = 0; - d.scrollbarsClipped = false; - - // Used to only resize the line number gutter when necessary (when - // the amount of lines crosses a boundary that makes its width change) - d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null; - // Set to true when a non-horizontal-scrolling line widget is - // added. As an optimization, line widget aligning is skipped when - // this is false. - d.alignWidgets = false; - - d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null; - - // Tracks the maximum line length so that the horizontal scrollbar - // can be kept static when scrolling. - d.maxLine = null; - d.maxLineLength = 0; - d.maxLineChanged = false; - - // Used for measuring wheel scrolling granularity - d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null; - - // True when shift is held down. - d.shift = false; - - // Used to track whether anything happened since the context menu - // was opened. - d.selForContextMenu = null; - - d.activeTouch = null; - - input.init(d); - } - - // STATE UPDATES - - // Used to get the editor into a consistent state again when options change. - - function loadMode(cm) { - cm.doc.mode = CodeMirror.getMode(cm.options, cm.doc.modeOption); - resetModeState(cm); - } - - function resetModeState(cm) { - cm.doc.iter(function(line) { - if (line.stateAfter) line.stateAfter = null; - if (line.styles) line.styles = null; - }); - cm.doc.frontier = cm.doc.first; - startWorker(cm, 100); - cm.state.modeGen++; - if (cm.curOp) regChange(cm); - } - - function wrappingChanged(cm) { - if (cm.options.lineWrapping) { - addClass(cm.display.wrapper, "CodeMirror-wrap"); - cm.display.sizer.style.minWidth = ""; - cm.display.sizerWidth = null; - } else { - rmClass(cm.display.wrapper, "CodeMirror-wrap"); - findMaxLine(cm); - } - estimateLineHeights(cm); - regChange(cm); - clearCaches(cm); - setTimeout(function(){updateScrollbars(cm);}, 100); - } - - // Returns a function that estimates the height of a line, to use as - // first approximation until the line becomes visible (and is thus - // properly measurable). - function estimateHeight(cm) { - var th = textHeight(cm.display), wrapping = cm.options.lineWrapping; - var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3); - return function(line) { - if (lineIsHidden(cm.doc, line)) return 0; - - var widgetsHeight = 0; - if (line.widgets) for (var i = 0; i < line.widgets.length; i++) { - if (line.widgets[i].height) widgetsHeight += line.widgets[i].height; - } - - if (wrapping) - return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th; - else - return widgetsHeight + th; - }; - } - - function estimateLineHeights(cm) { - var doc = cm.doc, est = estimateHeight(cm); - doc.iter(function(line) { - var estHeight = est(line); - if (estHeight != line.height) updateLineHeight(line, estHeight); - }); - } - - function themeChanged(cm) { - cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") + - cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-"); - clearCaches(cm); - } - - function guttersChanged(cm) { - updateGutters(cm); - regChange(cm); - setTimeout(function(){alignHorizontally(cm);}, 20); - } - - // Rebuild the gutter elements, ensure the margin to the left of the - // code matches their width. - function updateGutters(cm) { - var gutters = cm.display.gutters, specs = cm.options.gutters; - removeChildren(gutters); - for (var i = 0; i < specs.length; ++i) { - var gutterClass = specs[i]; - var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass)); - if (gutterClass == "CodeMirror-linenumbers") { - cm.display.lineGutter = gElt; - gElt.style.width = (cm.display.lineNumWidth || 1) + "px"; - } - } - gutters.style.display = i ? "" : "none"; - updateGutterSpace(cm); - } - - function updateGutterSpace(cm) { - var width = cm.display.gutters.offsetWidth; - cm.display.sizer.style.marginLeft = width + "px"; - } - - // Compute the character length of a line, taking into account - // collapsed ranges (see markText) that might hide parts, and join - // other lines onto it. - function lineLength(line) { - if (line.height == 0) return 0; - var len = line.text.length, merged, cur = line; - while (merged = collapsedSpanAtStart(cur)) { - var found = merged.find(0, true); - cur = found.from.line; - len += found.from.ch - found.to.ch; - } - cur = line; - while (merged = collapsedSpanAtEnd(cur)) { - var found = merged.find(0, true); - len -= cur.text.length - found.from.ch; - cur = found.to.line; - len += cur.text.length - found.to.ch; - } - return len; - } - - // Find the longest line in the document. - function findMaxLine(cm) { - var d = cm.display, doc = cm.doc; - d.maxLine = getLine(doc, doc.first); - d.maxLineLength = lineLength(d.maxLine); - d.maxLineChanged = true; - doc.iter(function(line) { - var len = lineLength(line); - if (len > d.maxLineLength) { - d.maxLineLength = len; - d.maxLine = line; - } - }); - } - - // Make sure the gutters options contains the element - // "CodeMirror-linenumbers" when the lineNumbers option is true. - function setGuttersForLineNumbers(options) { - var found = indexOf(options.gutters, "CodeMirror-linenumbers"); - if (found == -1 && options.lineNumbers) { - options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]); - } else if (found > -1 && !options.lineNumbers) { - options.gutters = options.gutters.slice(0); - options.gutters.splice(found, 1); - } - } - - // SCROLLBARS - - // Prepare DOM reads needed to update the scrollbars. Done in one - // shot to minimize update/measure roundtrips. - function measureForScrollbars(cm) { - var d = cm.display, gutterW = d.gutters.offsetWidth; - var docH = Math.round(cm.doc.height + paddingVert(cm.display)); - return { - clientHeight: d.scroller.clientHeight, - viewHeight: d.wrapper.clientHeight, - scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth, - viewWidth: d.wrapper.clientWidth, - barLeft: cm.options.fixedGutter ? gutterW : 0, - docHeight: docH, - scrollHeight: docH + scrollGap(cm) + d.barHeight, - nativeBarWidth: d.nativeBarWidth, - gutterWidth: gutterW - }; - } - - function NativeScrollbars(place, scroll, cm) { - this.cm = cm; - var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar"); - var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar"); - place(vert); place(horiz); - - on(vert, "scroll", function() { - if (vert.clientHeight) scroll(vert.scrollTop, "vertical"); - }); - on(horiz, "scroll", function() { - if (horiz.clientWidth) scroll(horiz.scrollLeft, "horizontal"); - }); - - this.checkedZeroWidth = false; - // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8). - if (ie && ie_version < 8) this.horiz.style.minHeight = this.vert.style.minWidth = "18px"; - } - - NativeScrollbars.prototype = copyObj({ - update: function(measure) { - var needsH = measure.scrollWidth > measure.clientWidth + 1; - var needsV = measure.scrollHeight > measure.clientHeight + 1; - var sWidth = measure.nativeBarWidth; - - if (needsV) { - this.vert.style.display = "block"; - this.vert.style.bottom = needsH ? sWidth + "px" : "0"; - var totalHeight = measure.viewHeight - (needsH ? sWidth : 0); - // A bug in IE8 can cause this value to be negative, so guard it. - this.vert.firstChild.style.height = - Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px"; - } else { - this.vert.style.display = ""; - this.vert.firstChild.style.height = "0"; - } - - if (needsH) { - this.horiz.style.display = "block"; - this.horiz.style.right = needsV ? sWidth + "px" : "0"; - this.horiz.style.left = measure.barLeft + "px"; - var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0); - this.horiz.firstChild.style.width = - (measure.scrollWidth - measure.clientWidth + totalWidth) + "px"; - } else { - this.horiz.style.display = ""; - this.horiz.firstChild.style.width = "0"; - } - - if (!this.checkedZeroWidth && measure.clientHeight > 0) { - if (sWidth == 0) this.zeroWidthHack(); - this.checkedZeroWidth = true; - } - - return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0}; - }, - setScrollLeft: function(pos) { - if (this.horiz.scrollLeft != pos) this.horiz.scrollLeft = pos; - if (this.disableHoriz) this.enableZeroWidthBar(this.horiz, this.disableHoriz); - }, - setScrollTop: function(pos) { - if (this.vert.scrollTop != pos) this.vert.scrollTop = pos; - if (this.disableVert) this.enableZeroWidthBar(this.vert, this.disableVert); - }, - zeroWidthHack: function() { - var w = mac && !mac_geMountainLion ? "12px" : "18px"; - this.horiz.style.height = this.vert.style.width = w; - this.horiz.style.pointerEvents = this.vert.style.pointerEvents = "none"; - this.disableHoriz = new Delayed; - this.disableVert = new Delayed; - }, - enableZeroWidthBar: function(bar, delay) { - bar.style.pointerEvents = "auto"; - function maybeDisable() { - // To find out whether the scrollbar is still visible, we - // check whether the element under the pixel in the bottom - // left corner of the scrollbar box is the scrollbar box - // itself (when the bar is still visible) or its filler child - // (when the bar is hidden). If it is still visible, we keep - // it enabled, if it's hidden, we disable pointer events. - var box = bar.getBoundingClientRect(); - var elt = document.elementFromPoint(box.left + 1, box.bottom - 1); - if (elt != bar) bar.style.pointerEvents = "none"; - else delay.set(1000, maybeDisable); - } - delay.set(1000, maybeDisable); - }, - clear: function() { - var parent = this.horiz.parentNode; - parent.removeChild(this.horiz); - parent.removeChild(this.vert); - } - }, NativeScrollbars.prototype); - - function NullScrollbars() {} - - NullScrollbars.prototype = copyObj({ - update: function() { return {bottom: 0, right: 0}; }, - setScrollLeft: function() {}, - setScrollTop: function() {}, - clear: function() {} - }, NullScrollbars.prototype); - - CodeMirror.scrollbarModel = {"native": NativeScrollbars, "null": NullScrollbars}; - - function initScrollbars(cm) { - if (cm.display.scrollbars) { - cm.display.scrollbars.clear(); - if (cm.display.scrollbars.addClass) - rmClass(cm.display.wrapper, cm.display.scrollbars.addClass); - } - - cm.display.scrollbars = new CodeMirror.scrollbarModel[cm.options.scrollbarStyle](function(node) { - cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller); - // Prevent clicks in the scrollbars from killing focus - on(node, "mousedown", function() { - if (cm.state.focused) setTimeout(function() { cm.display.input.focus(); }, 0); - }); - node.setAttribute("cm-not-content", "true"); - }, function(pos, axis) { - if (axis == "horizontal") setScrollLeft(cm, pos); - else setScrollTop(cm, pos); - }, cm); - if (cm.display.scrollbars.addClass) - addClass(cm.display.wrapper, cm.display.scrollbars.addClass); - } - - function updateScrollbars(cm, measure) { - if (!measure) measure = measureForScrollbars(cm); - var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight; - updateScrollbarsInner(cm, measure); - for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) { - if (startWidth != cm.display.barWidth && cm.options.lineWrapping) - updateHeightsInViewport(cm); - updateScrollbarsInner(cm, measureForScrollbars(cm)); - startWidth = cm.display.barWidth; startHeight = cm.display.barHeight; - } - } - - // Re-synchronize the fake scrollbars with the actual size of the - // content. - function updateScrollbarsInner(cm, measure) { - var d = cm.display; - var sizes = d.scrollbars.update(measure); - - d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px"; - d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px"; - d.heightForcer.style.borderBottom = sizes.bottom + "px solid transparent" - - if (sizes.right && sizes.bottom) { - d.scrollbarFiller.style.display = "block"; - d.scrollbarFiller.style.height = sizes.bottom + "px"; - d.scrollbarFiller.style.width = sizes.right + "px"; - } else d.scrollbarFiller.style.display = ""; - if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) { - d.gutterFiller.style.display = "block"; - d.gutterFiller.style.height = sizes.bottom + "px"; - d.gutterFiller.style.width = measure.gutterWidth + "px"; - } else d.gutterFiller.style.display = ""; - } - - // Compute the lines that are visible in a given viewport (defaults - // the the current scroll position). viewport may contain top, - // height, and ensure (see op.scrollToPos) properties. - function visibleLines(display, doc, viewport) { - var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop; - top = Math.floor(top - paddingTop(display)); - var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight; - - var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom); - // Ensure is a {from: {line, ch}, to: {line, ch}} object, and - // forces those lines into the viewport (if possible). - if (viewport && viewport.ensure) { - var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line; - if (ensureFrom < from) { - from = ensureFrom; - to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight); - } else if (Math.min(ensureTo, doc.lastLine()) >= to) { - from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight); - to = ensureTo; - } - } - return {from: from, to: Math.max(to, from + 1)}; - } - - // LINE NUMBERS - - // Re-align line numbers and gutter marks to compensate for - // horizontal scrolling. - function alignHorizontally(cm) { - var display = cm.display, view = display.view; - if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) return; - var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft; - var gutterW = display.gutters.offsetWidth, left = comp + "px"; - for (var i = 0; i < view.length; i++) if (!view[i].hidden) { - if (cm.options.fixedGutter && view[i].gutter) - view[i].gutter.style.left = left; - var align = view[i].alignable; - if (align) for (var j = 0; j < align.length; j++) - align[j].style.left = left; - } - if (cm.options.fixedGutter) - display.gutters.style.left = (comp + gutterW) + "px"; - } - - // Used to ensure that the line number gutter is still the right - // size for the current document size. Returns true when an update - // is needed. - function maybeUpdateLineNumberWidth(cm) { - if (!cm.options.lineNumbers) return false; - var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display; - if (last.length != display.lineNumChars) { - var test = display.measure.appendChild(elt("div", [elt("div", last)], - "CodeMirror-linenumber CodeMirror-gutter-elt")); - var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW; - display.lineGutter.style.width = ""; - display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1; - display.lineNumWidth = display.lineNumInnerWidth + padding; - display.lineNumChars = display.lineNumInnerWidth ? last.length : -1; - display.lineGutter.style.width = display.lineNumWidth + "px"; - updateGutterSpace(cm); - return true; - } - return false; - } - - function lineNumberFor(options, i) { - return String(options.lineNumberFormatter(i + options.firstLineNumber)); - } - - // Computes display.scroller.scrollLeft + display.gutters.offsetWidth, - // but using getBoundingClientRect to get a sub-pixel-accurate - // result. - function compensateForHScroll(display) { - return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left; - } - - // DISPLAY DRAWING - - function DisplayUpdate(cm, viewport, force) { - var display = cm.display; - - this.viewport = viewport; - // Store some values that we'll need later (but don't want to force a relayout for) - this.visible = visibleLines(display, cm.doc, viewport); - this.editorIsHidden = !display.wrapper.offsetWidth; - this.wrapperHeight = display.wrapper.clientHeight; - this.wrapperWidth = display.wrapper.clientWidth; - this.oldDisplayWidth = displayWidth(cm); - this.force = force; - this.dims = getDimensions(cm); - this.events = []; - } - - DisplayUpdate.prototype.signal = function(emitter, type) { - if (hasHandler(emitter, type)) - this.events.push(arguments); - }; - DisplayUpdate.prototype.finish = function() { - for (var i = 0; i < this.events.length; i++) - signal.apply(null, this.events[i]); - }; - - function maybeClipScrollbars(cm) { - var display = cm.display; - if (!display.scrollbarsClipped && display.scroller.offsetWidth) { - display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth; - display.heightForcer.style.height = scrollGap(cm) + "px"; - display.sizer.style.marginBottom = -display.nativeBarWidth + "px"; - display.sizer.style.borderRightWidth = scrollGap(cm) + "px"; - display.scrollbarsClipped = true; - } - } - - // Does the actual updating of the line display. Bails out - // (returning false) when there is nothing to be done and forced is - // false. - function updateDisplayIfNeeded(cm, update) { - var display = cm.display, doc = cm.doc; - - if (update.editorIsHidden) { - resetView(cm); - return false; - } - - // Bail out if the visible area is already rendered and nothing changed. - if (!update.force && - update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo && - (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) && - display.renderedView == display.view && countDirtyView(cm) == 0) - return false; - - if (maybeUpdateLineNumberWidth(cm)) { - resetView(cm); - update.dims = getDimensions(cm); - } - - // Compute a suitable new viewport (from & to) - var end = doc.first + doc.size; - var from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first); - var to = Math.min(end, update.visible.to + cm.options.viewportMargin); - if (display.viewFrom < from && from - display.viewFrom < 20) from = Math.max(doc.first, display.viewFrom); - if (display.viewTo > to && display.viewTo - to < 20) to = Math.min(end, display.viewTo); - if (sawCollapsedSpans) { - from = visualLineNo(cm.doc, from); - to = visualLineEndNo(cm.doc, to); - } - - var different = from != display.viewFrom || to != display.viewTo || - display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth; - adjustView(cm, from, to); - - display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom)); - // Position the mover div to align with the current scroll position - cm.display.mover.style.top = display.viewOffset + "px"; - - var toUpdate = countDirtyView(cm); - if (!different && toUpdate == 0 && !update.force && display.renderedView == display.view && - (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo)) - return false; - - // For big changes, we hide the enclosing element during the - // update, since that speeds up the operations on most browsers. - var focused = activeElt(); - if (toUpdate > 4) display.lineDiv.style.display = "none"; - patchDisplay(cm, display.updateLineNumbers, update.dims); - if (toUpdate > 4) display.lineDiv.style.display = ""; - display.renderedView = display.view; - // There might have been a widget with a focused element that got - // hidden or updated, if so re-focus it. - if (focused && activeElt() != focused && focused.offsetHeight) focused.focus(); - - // Prevent selection and cursors from interfering with the scroll - // width and height. - removeChildren(display.cursorDiv); - removeChildren(display.selectionDiv); - display.gutters.style.height = display.sizer.style.minHeight = 0; - - if (different) { - display.lastWrapHeight = update.wrapperHeight; - display.lastWrapWidth = update.wrapperWidth; - startWorker(cm, 400); - } - - display.updateLineNumbers = null; - - return true; - } - - function postUpdateDisplay(cm, update) { - var viewport = update.viewport; - for (var first = true;; first = false) { - if (!first || !cm.options.lineWrapping || update.oldDisplayWidth == displayWidth(cm)) { - // Clip forced viewport to actual scrollable area. - if (viewport && viewport.top != null) - viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top)}; - // Updated line heights might result in the drawn area not - // actually covering the viewport. Keep looping until it does. - update.visible = visibleLines(cm.display, cm.doc, viewport); - if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo) - break; - } - if (!updateDisplayIfNeeded(cm, update)) break; - updateHeightsInViewport(cm); - var barMeasure = measureForScrollbars(cm); - updateSelection(cm); - setDocumentHeight(cm, barMeasure); - updateScrollbars(cm, barMeasure); - } - - update.signal(cm, "update", cm); - if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) { - update.signal(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo); - cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo; - } - } - - function updateDisplaySimple(cm, viewport) { - var update = new DisplayUpdate(cm, viewport); - if (updateDisplayIfNeeded(cm, update)) { - updateHeightsInViewport(cm); - postUpdateDisplay(cm, update); - var barMeasure = measureForScrollbars(cm); - updateSelection(cm); - setDocumentHeight(cm, barMeasure); - updateScrollbars(cm, barMeasure); - update.finish(); - } - } - - function setDocumentHeight(cm, measure) { - cm.display.sizer.style.minHeight = measure.docHeight + "px"; - cm.display.heightForcer.style.top = measure.docHeight + "px"; - cm.display.gutters.style.height = Math.max(measure.docHeight + cm.display.barHeight + scrollGap(cm), - measure.clientHeight) + "px"; - } - - // Read the actual heights of the rendered lines, and update their - // stored heights to match. - function updateHeightsInViewport(cm) { - var display = cm.display; - var prevBottom = display.lineDiv.offsetTop; - for (var i = 0; i < display.view.length; i++) { - var cur = display.view[i], height; - if (cur.hidden) continue; - if (ie && ie_version < 8) { - var bot = cur.node.offsetTop + cur.node.offsetHeight; - height = bot - prevBottom; - prevBottom = bot; - } else { - var box = cur.node.getBoundingClientRect(); - height = box.bottom - box.top; - } - var diff = cur.line.height - height; - if (height < 2) height = textHeight(display); - if (diff > .001 || diff < -.001) { - updateLineHeight(cur.line, height); - updateWidgetHeight(cur.line); - if (cur.rest) for (var j = 0; j < cur.rest.length; j++) - updateWidgetHeight(cur.rest[j]); - } - } - } - - // Read and store the height of line widgets associated with the - // given line. - function updateWidgetHeight(line) { - if (line.widgets) for (var i = 0; i < line.widgets.length; ++i) - line.widgets[i].height = line.widgets[i].node.parentNode.offsetHeight; - } - - // Do a bulk-read of the DOM positions and sizes needed to draw the - // view, so that we don't interleave reading and writing to the DOM. - function getDimensions(cm) { - var d = cm.display, left = {}, width = {}; - var gutterLeft = d.gutters.clientLeft; - for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) { - left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft; - width[cm.options.gutters[i]] = n.clientWidth; - } - return {fixedPos: compensateForHScroll(d), - gutterTotalWidth: d.gutters.offsetWidth, - gutterLeft: left, - gutterWidth: width, - wrapperWidth: d.wrapper.clientWidth}; - } - - // Sync the actual display DOM structure with display.view, removing - // nodes for lines that are no longer in view, and creating the ones - // that are not there yet, and updating the ones that are out of - // date. - function patchDisplay(cm, updateNumbersFrom, dims) { - var display = cm.display, lineNumbers = cm.options.lineNumbers; - var container = display.lineDiv, cur = container.firstChild; - - function rm(node) { - var next = node.nextSibling; - // Works around a throw-scroll bug in OS X Webkit - if (webkit && mac && cm.display.currentWheelTarget == node) - node.style.display = "none"; - else - node.parentNode.removeChild(node); - return next; - } - - var view = display.view, lineN = display.viewFrom; - // Loop over the elements in the view, syncing cur (the DOM nodes - // in display.lineDiv) with the view as we go. - for (var i = 0; i < view.length; i++) { - var lineView = view[i]; - if (lineView.hidden) { - } else if (!lineView.node || lineView.node.parentNode != container) { // Not drawn yet - var node = buildLineElement(cm, lineView, lineN, dims); - container.insertBefore(node, cur); - } else { // Already drawn - while (cur != lineView.node) cur = rm(cur); - var updateNumber = lineNumbers && updateNumbersFrom != null && - updateNumbersFrom <= lineN && lineView.lineNumber; - if (lineView.changes) { - if (indexOf(lineView.changes, "gutter") > -1) updateNumber = false; - updateLineForChanges(cm, lineView, lineN, dims); - } - if (updateNumber) { - removeChildren(lineView.lineNumber); - lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN))); - } - cur = lineView.node.nextSibling; - } - lineN += lineView.size; - } - while (cur) cur = rm(cur); - } - - // When an aspect of a line changes, a string is added to - // lineView.changes. This updates the relevant part of the line's - // DOM structure. - function updateLineForChanges(cm, lineView, lineN, dims) { - for (var j = 0; j < lineView.changes.length; j++) { - var type = lineView.changes[j]; - if (type == "text") updateLineText(cm, lineView); - else if (type == "gutter") updateLineGutter(cm, lineView, lineN, dims); - else if (type == "class") updateLineClasses(lineView); - else if (type == "widget") updateLineWidgets(cm, lineView, dims); - } - lineView.changes = null; - } - - // Lines with gutter elements, widgets or a background class need to - // be wrapped, and have the extra elements added to the wrapper div - function ensureLineWrapped(lineView) { - if (lineView.node == lineView.text) { - lineView.node = elt("div", null, null, "position: relative"); - if (lineView.text.parentNode) - lineView.text.parentNode.replaceChild(lineView.node, lineView.text); - lineView.node.appendChild(lineView.text); - if (ie && ie_version < 8) lineView.node.style.zIndex = 2; - } - return lineView.node; - } - - function updateLineBackground(lineView) { - var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass; - if (cls) cls += " CodeMirror-linebackground"; - if (lineView.background) { - if (cls) lineView.background.className = cls; - else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null; } - } else if (cls) { - var wrap = ensureLineWrapped(lineView); - lineView.background = wrap.insertBefore(elt("div", null, cls), wrap.firstChild); - } - } - - // Wrapper around buildLineContent which will reuse the structure - // in display.externalMeasured when possible. - function getLineContent(cm, lineView) { - var ext = cm.display.externalMeasured; - if (ext && ext.line == lineView.line) { - cm.display.externalMeasured = null; - lineView.measure = ext.measure; - return ext.built; - } - return buildLineContent(cm, lineView); - } - - // Redraw the line's text. Interacts with the background and text - // classes because the mode may output tokens that influence these - // classes. - function updateLineText(cm, lineView) { - var cls = lineView.text.className; - var built = getLineContent(cm, lineView); - if (lineView.text == lineView.node) lineView.node = built.pre; - lineView.text.parentNode.replaceChild(built.pre, lineView.text); - lineView.text = built.pre; - if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) { - lineView.bgClass = built.bgClass; - lineView.textClass = built.textClass; - updateLineClasses(lineView); - } else if (cls) { - lineView.text.className = cls; - } - } - - function updateLineClasses(lineView) { - updateLineBackground(lineView); - if (lineView.line.wrapClass) - ensureLineWrapped(lineView).className = lineView.line.wrapClass; - else if (lineView.node != lineView.text) - lineView.node.className = ""; - var textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass; - lineView.text.className = textClass || ""; - } - - function updateLineGutter(cm, lineView, lineN, dims) { - if (lineView.gutter) { - lineView.node.removeChild(lineView.gutter); - lineView.gutter = null; - } - if (lineView.gutterBackground) { - lineView.node.removeChild(lineView.gutterBackground); - lineView.gutterBackground = null; - } - if (lineView.line.gutterClass) { - var wrap = ensureLineWrapped(lineView); - lineView.gutterBackground = elt("div", null, "CodeMirror-gutter-background " + lineView.line.gutterClass, - "left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + - "px; width: " + dims.gutterTotalWidth + "px"); - wrap.insertBefore(lineView.gutterBackground, lineView.text); - } - var markers = lineView.line.gutterMarkers; - if (cm.options.lineNumbers || markers) { - var wrap = ensureLineWrapped(lineView); - var gutterWrap = lineView.gutter = elt("div", null, "CodeMirror-gutter-wrapper", "left: " + - (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px"); - cm.display.input.setUneditable(gutterWrap); - wrap.insertBefore(gutterWrap, lineView.text); - if (lineView.line.gutterClass) - gutterWrap.className += " " + lineView.line.gutterClass; - if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"])) - lineView.lineNumber = gutterWrap.appendChild( - elt("div", lineNumberFor(cm.options, lineN), - "CodeMirror-linenumber CodeMirror-gutter-elt", - "left: " + dims.gutterLeft["CodeMirror-linenumbers"] + "px; width: " - + cm.display.lineNumInnerWidth + "px")); - if (markers) for (var k = 0; k < cm.options.gutters.length; ++k) { - var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id]; - if (found) - gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt", "left: " + - dims.gutterLeft[id] + "px; width: " + dims.gutterWidth[id] + "px")); - } - } - } - - function updateLineWidgets(cm, lineView, dims) { - if (lineView.alignable) lineView.alignable = null; - for (var node = lineView.node.firstChild, next; node; node = next) { - var next = node.nextSibling; - if (node.className == "CodeMirror-linewidget") - lineView.node.removeChild(node); - } - insertLineWidgets(cm, lineView, dims); - } - - // Build a line's DOM representation from scratch - function buildLineElement(cm, lineView, lineN, dims) { - var built = getLineContent(cm, lineView); - lineView.text = lineView.node = built.pre; - if (built.bgClass) lineView.bgClass = built.bgClass; - if (built.textClass) lineView.textClass = built.textClass; - - updateLineClasses(lineView); - updateLineGutter(cm, lineView, lineN, dims); - insertLineWidgets(cm, lineView, dims); - return lineView.node; - } - - // A lineView may contain multiple logical lines (when merged by - // collapsed spans). The widgets for all of them need to be drawn. - function insertLineWidgets(cm, lineView, dims) { - insertLineWidgetsFor(cm, lineView.line, lineView, dims, true); - if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++) - insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false); - } - - function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) { - if (!line.widgets) return; - var wrap = ensureLineWrapped(lineView); - for (var i = 0, ws = line.widgets; i < ws.length; ++i) { - var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget"); - if (!widget.handleMouseEvents) node.setAttribute("cm-ignore-events", "true"); - positionLineWidget(widget, node, lineView, dims); - cm.display.input.setUneditable(node); - if (allowAbove && widget.above) - wrap.insertBefore(node, lineView.gutter || lineView.text); - else - wrap.appendChild(node); - signalLater(widget, "redraw"); - } - } - - function positionLineWidget(widget, node, lineView, dims) { - if (widget.noHScroll) { - (lineView.alignable || (lineView.alignable = [])).push(node); - var width = dims.wrapperWidth; - node.style.left = dims.fixedPos + "px"; - if (!widget.coverGutter) { - width -= dims.gutterTotalWidth; - node.style.paddingLeft = dims.gutterTotalWidth + "px"; - } - node.style.width = width + "px"; - } - if (widget.coverGutter) { - node.style.zIndex = 5; - node.style.position = "relative"; - if (!widget.noHScroll) node.style.marginLeft = -dims.gutterTotalWidth + "px"; - } - } - - // POSITION OBJECT - - // A Pos instance represents a position within the text. - var Pos = CodeMirror.Pos = function(line, ch) { - if (!(this instanceof Pos)) return new Pos(line, ch); - this.line = line; this.ch = ch; - }; - - // Compare two positions, return 0 if they are the same, a negative - // number when a is less, and a positive number otherwise. - var cmp = CodeMirror.cmpPos = function(a, b) { return a.line - b.line || a.ch - b.ch; }; - - function copyPos(x) {return Pos(x.line, x.ch);} - function maxPos(a, b) { return cmp(a, b) < 0 ? b : a; } - function minPos(a, b) { return cmp(a, b) < 0 ? a : b; } - - // INPUT HANDLING - - function ensureFocus(cm) { - if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm); } - } - - // This will be set to an array of strings when copying, so that, - // when pasting, we know what kind of selections the copied text - // was made out of. - var lastCopied = null; - - function applyTextInput(cm, inserted, deleted, sel, origin) { - var doc = cm.doc; - cm.display.shift = false; - if (!sel) sel = doc.sel; - - var paste = cm.state.pasteIncoming || origin == "paste"; - var textLines = doc.splitLines(inserted), multiPaste = null; - // When pasing N lines into N selections, insert one line per selection - if (paste && sel.ranges.length > 1) { - if (lastCopied && lastCopied.join("\n") == inserted) { - if (sel.ranges.length % lastCopied.length == 0) { - multiPaste = []; - for (var i = 0; i < lastCopied.length; i++) - multiPaste.push(doc.splitLines(lastCopied[i])); - } - } else if (textLines.length == sel.ranges.length) { - multiPaste = map(textLines, function(l) { return [l]; }); - } - } - - // Normal behavior is to insert the new text into every selection - for (var i = sel.ranges.length - 1; i >= 0; i--) { - var range = sel.ranges[i]; - var from = range.from(), to = range.to(); - if (range.empty()) { - if (deleted && deleted > 0) // Handle deletion - from = Pos(from.line, from.ch - deleted); - else if (cm.state.overwrite && !paste) // Handle overwrite - to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length)); - } - var updateInput = cm.curOp.updateInput; - var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i % multiPaste.length] : textLines, - origin: origin || (paste ? "paste" : cm.state.cutIncoming ? "cut" : "+input")}; - makeChange(cm.doc, changeEvent); - signalLater(cm, "inputRead", cm, changeEvent); - } - if (inserted && !paste) - triggerElectric(cm, inserted); - - ensureCursorVisible(cm); - cm.curOp.updateInput = updateInput; - cm.curOp.typing = true; - cm.state.pasteIncoming = cm.state.cutIncoming = false; - } - - function handlePaste(e, cm) { - var pasted = e.clipboardData && e.clipboardData.getData("text/plain"); - if (pasted) { - e.preventDefault(); - if (!cm.isReadOnly() && !cm.options.disableInput) - runInOp(cm, function() { applyTextInput(cm, pasted, 0, null, "paste"); }); - return true; - } - } - - function triggerElectric(cm, inserted) { - // When an 'electric' character is inserted, immediately trigger a reindent - if (!cm.options.electricChars || !cm.options.smartIndent) return; - var sel = cm.doc.sel; - - for (var i = sel.ranges.length - 1; i >= 0; i--) { - var range = sel.ranges[i]; - if (range.head.ch > 100 || (i && sel.ranges[i - 1].head.line == range.head.line)) continue; - var mode = cm.getModeAt(range.head); - var indented = false; - if (mode.electricChars) { - for (var j = 0; j < mode.electricChars.length; j++) - if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) { - indented = indentLine(cm, range.head.line, "smart"); - break; - } - } else if (mode.electricInput) { - if (mode.electricInput.test(getLine(cm.doc, range.head.line).text.slice(0, range.head.ch))) - indented = indentLine(cm, range.head.line, "smart"); - } - if (indented) signalLater(cm, "electricInput", cm, range.head.line); - } - } - - function copyableRanges(cm) { - var text = [], ranges = []; - for (var i = 0; i < cm.doc.sel.ranges.length; i++) { - var line = cm.doc.sel.ranges[i].head.line; - var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)}; - ranges.push(lineRange); - text.push(cm.getRange(lineRange.anchor, lineRange.head)); - } - return {text: text, ranges: ranges}; - } - - function disableBrowserMagic(field) { - field.setAttribute("autocorrect", "off"); - field.setAttribute("autocapitalize", "off"); - field.setAttribute("spellcheck", "false"); - } - - // TEXTAREA INPUT STYLE - - function TextareaInput(cm) { - this.cm = cm; - // See input.poll and input.reset - this.prevInput = ""; - - // Flag that indicates whether we expect input to appear real soon - // now (after some event like 'keypress' or 'input') and are - // polling intensively. - this.pollingFast = false; - // Self-resetting timeout for the poller - this.polling = new Delayed(); - // Tracks when input.reset has punted to just putting a short - // string into the textarea instead of the full selection. - this.inaccurateSelection = false; - // Used to work around IE issue with selection being forgotten when focus moves away from textarea - this.hasSelection = false; - this.composing = null; - }; - - function hiddenTextarea() { - var te = elt("textarea", null, null, "position: absolute; padding: 0; width: 1px; height: 1em; outline: none"); - var div = elt("div", [te], null, "overflow: hidden; position: relative; width: 3px; height: 0px;"); - // The textarea is kept positioned near the cursor to prevent the - // fact that it'll be scrolled into view on input from scrolling - // our fake cursor out of view. On webkit, when wrap=off, paste is - // very slow. So make the area wide instead. - if (webkit) te.style.width = "1000px"; - else te.setAttribute("wrap", "off"); - // If border: 0; -- iOS fails to open keyboard (issue #1287) - if (ios) te.style.border = "1px solid black"; - disableBrowserMagic(te); - return div; - } - - TextareaInput.prototype = copyObj({ - init: function(display) { - var input = this, cm = this.cm; - - // Wraps and hides input textarea - var div = this.wrapper = hiddenTextarea(); - // The semihidden textarea that is focused when the editor is - // focused, and receives input. - var te = this.textarea = div.firstChild; - display.wrapper.insertBefore(div, display.wrapper.firstChild); - - // Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore) - if (ios) te.style.width = "0px"; - - on(te, "input", function() { - if (ie && ie_version >= 9 && input.hasSelection) input.hasSelection = null; - input.poll(); - }); - - on(te, "paste", function(e) { - if (signalDOMEvent(cm, e) || handlePaste(e, cm)) return - - cm.state.pasteIncoming = true; - input.fastPoll(); - }); - - function prepareCopyCut(e) { - if (signalDOMEvent(cm, e)) return - if (cm.somethingSelected()) { - lastCopied = cm.getSelections(); - if (input.inaccurateSelection) { - input.prevInput = ""; - input.inaccurateSelection = false; - te.value = lastCopied.join("\n"); - selectInput(te); - } - } else if (!cm.options.lineWiseCopyCut) { - return; - } else { - var ranges = copyableRanges(cm); - lastCopied = ranges.text; - if (e.type == "cut") { - cm.setSelections(ranges.ranges, null, sel_dontScroll); - } else { - input.prevInput = ""; - te.value = ranges.text.join("\n"); - selectInput(te); - } - } - if (e.type == "cut") cm.state.cutIncoming = true; - } - on(te, "cut", prepareCopyCut); - on(te, "copy", prepareCopyCut); - - on(display.scroller, "paste", function(e) { - if (eventInWidget(display, e) || signalDOMEvent(cm, e)) return; - cm.state.pasteIncoming = true; - input.focus(); - }); - - // Prevent normal selection in the editor (we handle our own) - on(display.lineSpace, "selectstart", function(e) { - if (!eventInWidget(display, e)) e_preventDefault(e); - }); - - on(te, "compositionstart", function() { - var start = cm.getCursor("from"); - if (input.composing) input.composing.range.clear() - input.composing = { - start: start, - range: cm.markText(start, cm.getCursor("to"), {className: "CodeMirror-composing"}) - }; - }); - on(te, "compositionend", function() { - if (input.composing) { - input.poll(); - input.composing.range.clear(); - input.composing = null; - } - }); - }, - - prepareSelection: function() { - // Redraw the selection and/or cursor - var cm = this.cm, display = cm.display, doc = cm.doc; - var result = prepareSelection(cm); - - // Move the hidden textarea near the cursor to prevent scrolling artifacts - if (cm.options.moveInputWithCursor) { - var headPos = cursorCoords(cm, doc.sel.primary().head, "div"); - var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect(); - result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10, - headPos.top + lineOff.top - wrapOff.top)); - result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10, - headPos.left + lineOff.left - wrapOff.left)); - } - - return result; - }, - - showSelection: function(drawn) { - var cm = this.cm, display = cm.display; - removeChildrenAndAdd(display.cursorDiv, drawn.cursors); - removeChildrenAndAdd(display.selectionDiv, drawn.selection); - if (drawn.teTop != null) { - this.wrapper.style.top = drawn.teTop + "px"; - this.wrapper.style.left = drawn.teLeft + "px"; - } - }, - - // Reset the input to correspond to the selection (or to be empty, - // when not typing and nothing is selected) - reset: function(typing) { - if (this.contextMenuPending) return; - var minimal, selected, cm = this.cm, doc = cm.doc; - if (cm.somethingSelected()) { - this.prevInput = ""; - var range = doc.sel.primary(); - minimal = hasCopyEvent && - (range.to().line - range.from().line > 100 || (selected = cm.getSelection()).length > 1000); - var content = minimal ? "-" : selected || cm.getSelection(); - this.textarea.value = content; - if (cm.state.focused) selectInput(this.textarea); - if (ie && ie_version >= 9) this.hasSelection = content; - } else if (!typing) { - this.prevInput = this.textarea.value = ""; - if (ie && ie_version >= 9) this.hasSelection = null; - } - this.inaccurateSelection = minimal; - }, - - getField: function() { return this.textarea; }, - - supportsTouch: function() { return false; }, - - focus: function() { - if (this.cm.options.readOnly != "nocursor" && (!mobile || activeElt() != this.textarea)) { - try { this.textarea.focus(); } - catch (e) {} // IE8 will throw if the textarea is display: none or not in DOM - } - }, - - blur: function() { this.textarea.blur(); }, - - resetPosition: function() { - this.wrapper.style.top = this.wrapper.style.left = 0; - }, - - receivedFocus: function() { this.slowPoll(); }, - - // Poll for input changes, using the normal rate of polling. This - // runs as long as the editor is focused. - slowPoll: function() { - var input = this; - if (input.pollingFast) return; - input.polling.set(this.cm.options.pollInterval, function() { - input.poll(); - if (input.cm.state.focused) input.slowPoll(); - }); - }, - - // When an event has just come in that is likely to add or change - // something in the input textarea, we poll faster, to ensure that - // the change appears on the screen quickly. - fastPoll: function() { - var missed = false, input = this; - input.pollingFast = true; - function p() { - var changed = input.poll(); - if (!changed && !missed) {missed = true; input.polling.set(60, p);} - else {input.pollingFast = false; input.slowPoll();} - } - input.polling.set(20, p); - }, - - // Read input from the textarea, and update the document to match. - // When something is selected, it is present in the textarea, and - // selected (unless it is huge, in which case a placeholder is - // used). When nothing is selected, the cursor sits after previously - // seen text (can be empty), which is stored in prevInput (we must - // not reset the textarea when typing, because that breaks IME). - poll: function() { - var cm = this.cm, input = this.textarea, prevInput = this.prevInput; - // Since this is called a *lot*, try to bail out as cheaply as - // possible when it is clear that nothing happened. hasSelection - // will be the case when there is a lot of text in the textarea, - // in which case reading its value would be expensive. - if (this.contextMenuPending || !cm.state.focused || - (hasSelection(input) && !prevInput && !this.composing) || - cm.isReadOnly() || cm.options.disableInput || cm.state.keySeq) - return false; - - var text = input.value; - // If nothing changed, bail. - if (text == prevInput && !cm.somethingSelected()) return false; - // Work around nonsensical selection resetting in IE9/10, and - // inexplicable appearance of private area unicode characters on - // some key combos in Mac (#2689). - if (ie && ie_version >= 9 && this.hasSelection === text || - mac && /[\uf700-\uf7ff]/.test(text)) { - cm.display.input.reset(); - return false; - } - - if (cm.doc.sel == cm.display.selForContextMenu) { - var first = text.charCodeAt(0); - if (first == 0x200b && !prevInput) prevInput = "\u200b"; - if (first == 0x21da) { this.reset(); return this.cm.execCommand("undo"); } - } - // Find the part of the input that is actually new - var same = 0, l = Math.min(prevInput.length, text.length); - while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) ++same; - - var self = this; - runInOp(cm, function() { - applyTextInput(cm, text.slice(same), prevInput.length - same, - null, self.composing ? "*compose" : null); - - // Don't leave long text in the textarea, since it makes further polling slow - if (text.length > 1000 || text.indexOf("\n") > -1) input.value = self.prevInput = ""; - else self.prevInput = text; - - if (self.composing) { - self.composing.range.clear(); - self.composing.range = cm.markText(self.composing.start, cm.getCursor("to"), - {className: "CodeMirror-composing"}); - } - }); - return true; - }, - - ensurePolled: function() { - if (this.pollingFast && this.poll()) this.pollingFast = false; - }, - - onKeyPress: function() { - if (ie && ie_version >= 9) this.hasSelection = null; - this.fastPoll(); - }, - - onContextMenu: function(e) { - var input = this, cm = input.cm, display = cm.display, te = input.textarea; - var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop; - if (!pos || presto) return; // Opera is difficult. - - // Reset the current text selection only if the click is done outside of the selection - // and 'resetSelectionOnContextMenu' option is true. - var reset = cm.options.resetSelectionOnContextMenu; - if (reset && cm.doc.sel.contains(pos) == -1) - operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll); - - var oldCSS = te.style.cssText, oldWrapperCSS = input.wrapper.style.cssText; - input.wrapper.style.cssText = "position: absolute" - var wrapperBox = input.wrapper.getBoundingClientRect() - te.style.cssText = "position: absolute; width: 30px; height: 30px; top: " + (e.clientY - wrapperBox.top - 5) + - "px; left: " + (e.clientX - wrapperBox.left - 5) + "px; z-index: 1000; background: " + - (ie ? "rgba(255, 255, 255, .05)" : "transparent") + - "; outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);"; - if (webkit) var oldScrollY = window.scrollY; // Work around Chrome issue (#2712) - display.input.focus(); - if (webkit) window.scrollTo(null, oldScrollY); - display.input.reset(); - // Adds "Select all" to context menu in FF - if (!cm.somethingSelected()) te.value = input.prevInput = " "; - input.contextMenuPending = true; - display.selForContextMenu = cm.doc.sel; - clearTimeout(display.detectingSelectAll); - - // Select-all will be greyed out if there's nothing to select, so - // this adds a zero-width space so that we can later check whether - // it got selected. - function prepareSelectAllHack() { - if (te.selectionStart != null) { - var selected = cm.somethingSelected(); - var extval = "\u200b" + (selected ? te.value : ""); - te.value = "\u21da"; // Used to catch context-menu undo - te.value = extval; - input.prevInput = selected ? "" : "\u200b"; - te.selectionStart = 1; te.selectionEnd = extval.length; - // Re-set this, in case some other handler touched the - // selection in the meantime. - display.selForContextMenu = cm.doc.sel; - } - } - function rehide() { - input.contextMenuPending = false; - input.wrapper.style.cssText = oldWrapperCSS - te.style.cssText = oldCSS; - if (ie && ie_version < 9) display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos); - - // Try to detect the user choosing select-all - if (te.selectionStart != null) { - if (!ie || (ie && ie_version < 9)) prepareSelectAllHack(); - var i = 0, poll = function() { - if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0 && - te.selectionEnd > 0 && input.prevInput == "\u200b") - operation(cm, commands.selectAll)(cm); - else if (i++ < 10) display.detectingSelectAll = setTimeout(poll, 500); - else display.input.reset(); - }; - display.detectingSelectAll = setTimeout(poll, 200); - } - } - - if (ie && ie_version >= 9) prepareSelectAllHack(); - if (captureRightClick) { - e_stop(e); - var mouseup = function() { - off(window, "mouseup", mouseup); - setTimeout(rehide, 20); - }; - on(window, "mouseup", mouseup); - } else { - setTimeout(rehide, 50); - } - }, - - readOnlyChanged: function(val) { - if (!val) this.reset(); - }, - - setUneditable: nothing, - - needsContentAttribute: false - }, TextareaInput.prototype); - - // CONTENTEDITABLE INPUT STYLE - - function ContentEditableInput(cm) { - this.cm = cm; - this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null; - this.polling = new Delayed(); - this.gracePeriod = false; - } - - ContentEditableInput.prototype = copyObj({ - init: function(display) { - var input = this, cm = input.cm; - var div = input.div = display.lineDiv; - disableBrowserMagic(div); - - on(div, "paste", function(e) { - if (!signalDOMEvent(cm, e)) handlePaste(e, cm); - }) - - on(div, "compositionstart", function(e) { - var data = e.data; - input.composing = {sel: cm.doc.sel, data: data, startData: data}; - if (!data) return; - var prim = cm.doc.sel.primary(); - var line = cm.getLine(prim.head.line); - var found = line.indexOf(data, Math.max(0, prim.head.ch - data.length)); - if (found > -1 && found <= prim.head.ch) - input.composing.sel = simpleSelection(Pos(prim.head.line, found), - Pos(prim.head.line, found + data.length)); - }); - on(div, "compositionupdate", function(e) { - input.composing.data = e.data; - }); - on(div, "compositionend", function(e) { - var ours = input.composing; - if (!ours) return; - if (e.data != ours.startData && !/\u200b/.test(e.data)) - ours.data = e.data; - // Need a small delay to prevent other code (input event, - // selection polling) from doing damage when fired right after - // compositionend. - setTimeout(function() { - if (!ours.handled) - input.applyComposition(ours); - if (input.composing == ours) - input.composing = null; - }, 50); - }); - - on(div, "touchstart", function() { - input.forceCompositionEnd(); - }); - - on(div, "input", function() { - if (input.composing) return; - if (cm.isReadOnly() || !input.pollContent()) - runInOp(input.cm, function() {regChange(cm);}); - }); - - function onCopyCut(e) { - if (signalDOMEvent(cm, e)) return - if (cm.somethingSelected()) { - lastCopied = cm.getSelections(); - if (e.type == "cut") cm.replaceSelection("", null, "cut"); - } else if (!cm.options.lineWiseCopyCut) { - return; - } else { - var ranges = copyableRanges(cm); - lastCopied = ranges.text; - if (e.type == "cut") { - cm.operation(function() { - cm.setSelections(ranges.ranges, 0, sel_dontScroll); - cm.replaceSelection("", null, "cut"); - }); - } - } - // iOS exposes the clipboard API, but seems to discard content inserted into it - if (e.clipboardData && !ios) { - e.preventDefault(); - e.clipboardData.clearData(); - e.clipboardData.setData("text/plain", lastCopied.join("\n")); - } else { - // Old-fashioned briefly-focus-a-textarea hack - var kludge = hiddenTextarea(), te = kludge.firstChild; - cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild); - te.value = lastCopied.join("\n"); - var hadFocus = document.activeElement; - selectInput(te); - setTimeout(function() { - cm.display.lineSpace.removeChild(kludge); - hadFocus.focus(); - }, 50); - } - } - on(div, "copy", onCopyCut); - on(div, "cut", onCopyCut); - }, - - prepareSelection: function() { - var result = prepareSelection(this.cm, false); - result.focus = this.cm.state.focused; - return result; - }, - - showSelection: function(info) { - if (!info || !this.cm.display.view.length) return; - if (info.focus) this.showPrimarySelection(); - this.showMultipleSelections(info); - }, - - showPrimarySelection: function() { - var sel = window.getSelection(), prim = this.cm.doc.sel.primary(); - var curAnchor = domToPos(this.cm, sel.anchorNode, sel.anchorOffset); - var curFocus = domToPos(this.cm, sel.focusNode, sel.focusOffset); - if (curAnchor && !curAnchor.bad && curFocus && !curFocus.bad && - cmp(minPos(curAnchor, curFocus), prim.from()) == 0 && - cmp(maxPos(curAnchor, curFocus), prim.to()) == 0) - return; - - var start = posToDOM(this.cm, prim.from()); - var end = posToDOM(this.cm, prim.to()); - if (!start && !end) return; - - var view = this.cm.display.view; - var old = sel.rangeCount && sel.getRangeAt(0); - if (!start) { - start = {node: view[0].measure.map[2], offset: 0}; - } else if (!end) { // FIXME dangerously hacky - var measure = view[view.length - 1].measure; - var map = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map; - end = {node: map[map.length - 1], offset: map[map.length - 2] - map[map.length - 3]}; - } - - try { var rng = range(start.node, start.offset, end.offset, end.node); } - catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible - if (rng) { - if (!gecko && this.cm.state.focused) { - sel.collapse(start.node, start.offset); - if (!rng.collapsed) sel.addRange(rng); - } else { - sel.removeAllRanges(); - sel.addRange(rng); - } - if (old && sel.anchorNode == null) sel.addRange(old); - else if (gecko) this.startGracePeriod(); - } - this.rememberSelection(); - }, - - startGracePeriod: function() { - var input = this; - clearTimeout(this.gracePeriod); - this.gracePeriod = setTimeout(function() { - input.gracePeriod = false; - if (input.selectionChanged()) - input.cm.operation(function() { input.cm.curOp.selectionChanged = true; }); - }, 20); - }, - - showMultipleSelections: function(info) { - removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors); - removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection); - }, - - rememberSelection: function() { - var sel = window.getSelection(); - this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset; - this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset; - }, - - selectionInEditor: function() { - var sel = window.getSelection(); - if (!sel.rangeCount) return false; - var node = sel.getRangeAt(0).commonAncestorContainer; - return contains(this.div, node); - }, - - focus: function() { - if (this.cm.options.readOnly != "nocursor") this.div.focus(); - }, - blur: function() { this.div.blur(); }, - getField: function() { return this.div; }, - - supportsTouch: function() { return true; }, - - receivedFocus: function() { - var input = this; - if (this.selectionInEditor()) - this.pollSelection(); - else - runInOp(this.cm, function() { input.cm.curOp.selectionChanged = true; }); - - function poll() { - if (input.cm.state.focused) { - input.pollSelection(); - input.polling.set(input.cm.options.pollInterval, poll); - } - } - this.polling.set(this.cm.options.pollInterval, poll); - }, - - selectionChanged: function() { - var sel = window.getSelection(); - return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset || - sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset; - }, - - pollSelection: function() { - if (!this.composing && !this.gracePeriod && this.selectionChanged()) { - var sel = window.getSelection(), cm = this.cm; - this.rememberSelection(); - var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset); - var head = domToPos(cm, sel.focusNode, sel.focusOffset); - if (anchor && head) runInOp(cm, function() { - setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll); - if (anchor.bad || head.bad) cm.curOp.selectionChanged = true; - }); - } - }, - - pollContent: function() { - var cm = this.cm, display = cm.display, sel = cm.doc.sel.primary(); - var from = sel.from(), to = sel.to(); - if (from.line < display.viewFrom || to.line > display.viewTo - 1) return false; - - var fromIndex; - if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) { - var fromLine = lineNo(display.view[0].line); - var fromNode = display.view[0].node; - } else { - var fromLine = lineNo(display.view[fromIndex].line); - var fromNode = display.view[fromIndex - 1].node.nextSibling; - } - var toIndex = findViewIndex(cm, to.line); - if (toIndex == display.view.length - 1) { - var toLine = display.viewTo - 1; - var toNode = display.lineDiv.lastChild; - } else { - var toLine = lineNo(display.view[toIndex + 1].line) - 1; - var toNode = display.view[toIndex + 1].node.previousSibling; - } - - var newText = cm.doc.splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine)); - var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length)); - while (newText.length > 1 && oldText.length > 1) { - if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine--; } - else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++; } - else break; - } - - var cutFront = 0, cutEnd = 0; - var newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length); - while (cutFront < maxCutFront && newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront)) - ++cutFront; - var newBot = lst(newText), oldBot = lst(oldText); - var maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0), - oldBot.length - (oldText.length == 1 ? cutFront : 0)); - while (cutEnd < maxCutEnd && - newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1)) - ++cutEnd; - - newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd); - newText[0] = newText[0].slice(cutFront); - - var chFrom = Pos(fromLine, cutFront); - var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0); - if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) { - replaceRange(cm.doc, newText, chFrom, chTo, "+input"); - return true; - } - }, - - ensurePolled: function() { - this.forceCompositionEnd(); - }, - reset: function() { - this.forceCompositionEnd(); - }, - forceCompositionEnd: function() { - if (!this.composing || this.composing.handled) return; - this.applyComposition(this.composing); - this.composing.handled = true; - this.div.blur(); - this.div.focus(); - }, - applyComposition: function(composing) { - if (this.cm.isReadOnly()) - operation(this.cm, regChange)(this.cm) - else if (composing.data && composing.data != composing.startData) - operation(this.cm, applyTextInput)(this.cm, composing.data, 0, composing.sel); - }, - - setUneditable: function(node) { - node.contentEditable = "false" - }, - - onKeyPress: function(e) { - e.preventDefault(); - if (!this.cm.isReadOnly()) - operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0); - }, - - readOnlyChanged: function(val) { - this.div.contentEditable = String(val != "nocursor") - }, - - onContextMenu: nothing, - resetPosition: nothing, - - needsContentAttribute: true - }, ContentEditableInput.prototype); - - function posToDOM(cm, pos) { - var view = findViewForLine(cm, pos.line); - if (!view || view.hidden) return null; - var line = getLine(cm.doc, pos.line); - var info = mapFromLineView(view, line, pos.line); - - var order = getOrder(line), side = "left"; - if (order) { - var partPos = getBidiPartAt(order, pos.ch); - side = partPos % 2 ? "right" : "left"; - } - var result = nodeAndOffsetInLineMap(info.map, pos.ch, side); - result.offset = result.collapse == "right" ? result.end : result.start; - return result; - } - - function badPos(pos, bad) { if (bad) pos.bad = true; return pos; } - - function domToPos(cm, node, offset) { - var lineNode; - if (node == cm.display.lineDiv) { - lineNode = cm.display.lineDiv.childNodes[offset]; - if (!lineNode) return badPos(cm.clipPos(Pos(cm.display.viewTo - 1)), true); - node = null; offset = 0; - } else { - for (lineNode = node;; lineNode = lineNode.parentNode) { - if (!lineNode || lineNode == cm.display.lineDiv) return null; - if (lineNode.parentNode && lineNode.parentNode == cm.display.lineDiv) break; - } - } - for (var i = 0; i < cm.display.view.length; i++) { - var lineView = cm.display.view[i]; - if (lineView.node == lineNode) - return locateNodeInLineView(lineView, node, offset); - } - } - - function locateNodeInLineView(lineView, node, offset) { - var wrapper = lineView.text.firstChild, bad = false; - if (!node || !contains(wrapper, node)) return badPos(Pos(lineNo(lineView.line), 0), true); - if (node == wrapper) { - bad = true; - node = wrapper.childNodes[offset]; - offset = 0; - if (!node) { - var line = lineView.rest ? lst(lineView.rest) : lineView.line; - return badPos(Pos(lineNo(line), line.text.length), bad); - } - } - - var textNode = node.nodeType == 3 ? node : null, topNode = node; - if (!textNode && node.childNodes.length == 1 && node.firstChild.nodeType == 3) { - textNode = node.firstChild; - if (offset) offset = textNode.nodeValue.length; - } - while (topNode.parentNode != wrapper) topNode = topNode.parentNode; - var measure = lineView.measure, maps = measure.maps; - - function find(textNode, topNode, offset) { - for (var i = -1; i < (maps ? maps.length : 0); i++) { - var map = i < 0 ? measure.map : maps[i]; - for (var j = 0; j < map.length; j += 3) { - var curNode = map[j + 2]; - if (curNode == textNode || curNode == topNode) { - var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]); - var ch = map[j] + offset; - if (offset < 0 || curNode != textNode) ch = map[j + (offset ? 1 : 0)]; - return Pos(line, ch); - } - } - } - } - var found = find(textNode, topNode, offset); - if (found) return badPos(found, bad); - - // FIXME this is all really shaky. might handle the few cases it needs to handle, but likely to cause problems - for (var after = topNode.nextSibling, dist = textNode ? textNode.nodeValue.length - offset : 0; after; after = after.nextSibling) { - found = find(after, after.firstChild, 0); - if (found) - return badPos(Pos(found.line, found.ch - dist), bad); - else - dist += after.textContent.length; - } - for (var before = topNode.previousSibling, dist = offset; before; before = before.previousSibling) { - found = find(before, before.firstChild, -1); - if (found) - return badPos(Pos(found.line, found.ch + dist), bad); - else - dist += after.textContent.length; - } - } - - function domTextBetween(cm, from, to, fromLine, toLine) { - var text = "", closing = false, lineSep = cm.doc.lineSeparator(); - function recognizeMarker(id) { return function(marker) { return marker.id == id; }; } - function walk(node) { - if (node.nodeType == 1) { - var cmText = node.getAttribute("cm-text"); - if (cmText != null) { - if (cmText == "") cmText = node.textContent.replace(/\u200b/g, ""); - text += cmText; - return; - } - var markerID = node.getAttribute("cm-marker"), range; - if (markerID) { - var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID)); - if (found.length && (range = found[0].find())) - text += getBetween(cm.doc, range.from, range.to).join(lineSep); - return; - } - if (node.getAttribute("contenteditable") == "false") return; - for (var i = 0; i < node.childNodes.length; i++) - walk(node.childNodes[i]); - if (/^(pre|div|p)$/i.test(node.nodeName)) - closing = true; - } else if (node.nodeType == 3) { - var val = node.nodeValue; - if (!val) return; - if (closing) { - text += lineSep; - closing = false; - } - text += val; - } - } - for (;;) { - walk(from); - if (from == to) break; - from = from.nextSibling; - } - return text; - } - - CodeMirror.inputStyles = {"textarea": TextareaInput, "contenteditable": ContentEditableInput}; - - // SELECTION / CURSOR - - // Selection objects are immutable. A new one is created every time - // the selection changes. A selection is one or more non-overlapping - // (and non-touching) ranges, sorted, and an integer that indicates - // which one is the primary selection (the one that's scrolled into - // view, that getCursor returns, etc). - function Selection(ranges, primIndex) { - this.ranges = ranges; - this.primIndex = primIndex; - } - - Selection.prototype = { - primary: function() { return this.ranges[this.primIndex]; }, - equals: function(other) { - if (other == this) return true; - if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) return false; - for (var i = 0; i < this.ranges.length; i++) { - var here = this.ranges[i], there = other.ranges[i]; - if (cmp(here.anchor, there.anchor) != 0 || cmp(here.head, there.head) != 0) return false; - } - return true; - }, - deepCopy: function() { - for (var out = [], i = 0; i < this.ranges.length; i++) - out[i] = new Range(copyPos(this.ranges[i].anchor), copyPos(this.ranges[i].head)); - return new Selection(out, this.primIndex); - }, - somethingSelected: function() { - for (var i = 0; i < this.ranges.length; i++) - if (!this.ranges[i].empty()) return true; - return false; - }, - contains: function(pos, end) { - if (!end) end = pos; - for (var i = 0; i < this.ranges.length; i++) { - var range = this.ranges[i]; - if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0) - return i; - } - return -1; - } - }; - - function Range(anchor, head) { - this.anchor = anchor; this.head = head; - } - - Range.prototype = { - from: function() { return minPos(this.anchor, this.head); }, - to: function() { return maxPos(this.anchor, this.head); }, - empty: function() { - return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch; - } - }; - - // Take an unsorted, potentially overlapping set of ranges, and - // build a selection out of it. 'Consumes' ranges array (modifying - // it). - function normalizeSelection(ranges, primIndex) { - var prim = ranges[primIndex]; - ranges.sort(function(a, b) { return cmp(a.from(), b.from()); }); - primIndex = indexOf(ranges, prim); - for (var i = 1; i < ranges.length; i++) { - var cur = ranges[i], prev = ranges[i - 1]; - if (cmp(prev.to(), cur.from()) >= 0) { - var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to()); - var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head; - if (i <= primIndex) --primIndex; - ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to)); - } - } - return new Selection(ranges, primIndex); - } - - function simpleSelection(anchor, head) { - return new Selection([new Range(anchor, head || anchor)], 0); - } - - // Most of the external API clips given positions to make sure they - // actually exist within the document. - function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1));} - function clipPos(doc, pos) { - if (pos.line < doc.first) return Pos(doc.first, 0); - var last = doc.first + doc.size - 1; - if (pos.line > last) return Pos(last, getLine(doc, last).text.length); - return clipToLen(pos, getLine(doc, pos.line).text.length); - } - function clipToLen(pos, linelen) { - var ch = pos.ch; - if (ch == null || ch > linelen) return Pos(pos.line, linelen); - else if (ch < 0) return Pos(pos.line, 0); - else return pos; - } - function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size;} - function clipPosArray(doc, array) { - for (var out = [], i = 0; i < array.length; i++) out[i] = clipPos(doc, array[i]); - return out; - } - - // SELECTION UPDATES - - // The 'scroll' parameter given to many of these indicated whether - // the new cursor position should be scrolled into view after - // modifying the selection. - - // If shift is held or the extend flag is set, extends a range to - // include a given position (and optionally a second position). - // Otherwise, simply returns the range between the given positions. - // Used for cursor motion and such. - function extendRange(doc, range, head, other) { - if (doc.cm && doc.cm.display.shift || doc.extend) { - var anchor = range.anchor; - if (other) { - var posBefore = cmp(head, anchor) < 0; - if (posBefore != (cmp(other, anchor) < 0)) { - anchor = head; - head = other; - } else if (posBefore != (cmp(head, other) < 0)) { - head = other; - } - } - return new Range(anchor, head); - } else { - return new Range(other || head, head); - } - } - - // Extend the primary selection range, discard the rest. - function extendSelection(doc, head, other, options) { - setSelection(doc, new Selection([extendRange(doc, doc.sel.primary(), head, other)], 0), options); - } - - // Extend all selections (pos is an array of selections with length - // equal the number of selections) - function extendSelections(doc, heads, options) { - for (var out = [], i = 0; i < doc.sel.ranges.length; i++) - out[i] = extendRange(doc, doc.sel.ranges[i], heads[i], null); - var newSel = normalizeSelection(out, doc.sel.primIndex); - setSelection(doc, newSel, options); - } - - // Updates a single range in the selection. - function replaceOneSelection(doc, i, range, options) { - var ranges = doc.sel.ranges.slice(0); - ranges[i] = range; - setSelection(doc, normalizeSelection(ranges, doc.sel.primIndex), options); - } - - // Reset the selection to a single range. - function setSimpleSelection(doc, anchor, head, options) { - setSelection(doc, simpleSelection(anchor, head), options); - } - - // Give beforeSelectionChange handlers a change to influence a - // selection update. - function filterSelectionChange(doc, sel, options) { - var obj = { - ranges: sel.ranges, - update: function(ranges) { - this.ranges = []; - for (var i = 0; i < ranges.length; i++) - this.ranges[i] = new Range(clipPos(doc, ranges[i].anchor), - clipPos(doc, ranges[i].head)); - }, - origin: options && options.origin - }; - signal(doc, "beforeSelectionChange", doc, obj); - if (doc.cm) signal(doc.cm, "beforeSelectionChange", doc.cm, obj); - if (obj.ranges != sel.ranges) return normalizeSelection(obj.ranges, obj.ranges.length - 1); - else return sel; - } - - function setSelectionReplaceHistory(doc, sel, options) { - var done = doc.history.done, last = lst(done); - if (last && last.ranges) { - done[done.length - 1] = sel; - setSelectionNoUndo(doc, sel, options); - } else { - setSelection(doc, sel, options); - } - } - - // Set a new selection. - function setSelection(doc, sel, options) { - setSelectionNoUndo(doc, sel, options); - addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options); - } - - function setSelectionNoUndo(doc, sel, options) { - if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange")) - sel = filterSelectionChange(doc, sel, options); - - var bias = options && options.bias || - (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1); - setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true)); - - if (!(options && options.scroll === false) && doc.cm) - ensureCursorVisible(doc.cm); - } - - function setSelectionInner(doc, sel) { - if (sel.equals(doc.sel)) return; - - doc.sel = sel; - - if (doc.cm) { - doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged = true; - signalCursorActivity(doc.cm); - } - signalLater(doc, "cursorActivity", doc); - } - - // Verify that the selection does not partially select any atomic - // marked ranges. - function reCheckSelection(doc) { - setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false), sel_dontScroll); - } - - // Return a selection that does not partially select any atomic - // ranges. - function skipAtomicInSelection(doc, sel, bias, mayClear) { - var out; - for (var i = 0; i < sel.ranges.length; i++) { - var range = sel.ranges[i]; - var old = sel.ranges.length == doc.sel.ranges.length && doc.sel.ranges[i]; - var newAnchor = skipAtomic(doc, range.anchor, old && old.anchor, bias, mayClear); - var newHead = skipAtomic(doc, range.head, old && old.head, bias, mayClear); - if (out || newAnchor != range.anchor || newHead != range.head) { - if (!out) out = sel.ranges.slice(0, i); - out[i] = new Range(newAnchor, newHead); - } - } - return out ? normalizeSelection(out, sel.primIndex) : sel; - } - - function skipAtomicInner(doc, pos, oldPos, dir, mayClear) { - var line = getLine(doc, pos.line); - if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) { - var sp = line.markedSpans[i], m = sp.marker; - if ((sp.from == null || (m.inclusiveLeft ? sp.from <= pos.ch : sp.from < pos.ch)) && - (sp.to == null || (m.inclusiveRight ? sp.to >= pos.ch : sp.to > pos.ch))) { - if (mayClear) { - signal(m, "beforeCursorEnter"); - if (m.explicitlyCleared) { - if (!line.markedSpans) break; - else {--i; continue;} - } - } - if (!m.atomic) continue; - - if (oldPos) { - var near = m.find(dir < 0 ? 1 : -1), diff; - if (dir < 0 ? m.inclusiveRight : m.inclusiveLeft) near = movePos(doc, near, -dir, line); - if (near && near.line == pos.line && (diff = cmp(near, oldPos)) && (dir < 0 ? diff < 0 : diff > 0)) - return skipAtomicInner(doc, near, pos, dir, mayClear); - } - - var far = m.find(dir < 0 ? -1 : 1); - if (dir < 0 ? m.inclusiveLeft : m.inclusiveRight) far = movePos(doc, far, dir, line); - return far ? skipAtomicInner(doc, far, pos, dir, mayClear) : null; - } - } - return pos; - } - - // Ensure a given position is not inside an atomic range. - function skipAtomic(doc, pos, oldPos, bias, mayClear) { - var dir = bias || 1; - var found = skipAtomicInner(doc, pos, oldPos, dir, mayClear) || - (!mayClear && skipAtomicInner(doc, pos, oldPos, dir, true)) || - skipAtomicInner(doc, pos, oldPos, -dir, mayClear) || - (!mayClear && skipAtomicInner(doc, pos, oldPos, -dir, true)); - if (!found) { - doc.cantEdit = true; - return Pos(doc.first, 0); - } - return found; - } - - function movePos(doc, pos, dir, line) { - if (dir < 0 && pos.ch == 0) { - if (pos.line > doc.first) return clipPos(doc, Pos(pos.line - 1)); - else return null; - } else if (dir > 0 && pos.ch == (line || getLine(doc, pos.line)).text.length) { - if (pos.line < doc.first + doc.size - 1) return Pos(pos.line + 1, 0); - else return null; - } else { - return new Pos(pos.line, pos.ch + dir); - } - } - - // SELECTION DRAWING - - function updateSelection(cm) { - cm.display.input.showSelection(cm.display.input.prepareSelection()); - } - - function prepareSelection(cm, primary) { - var doc = cm.doc, result = {}; - var curFragment = result.cursors = document.createDocumentFragment(); - var selFragment = result.selection = document.createDocumentFragment(); - - for (var i = 0; i < doc.sel.ranges.length; i++) { - if (primary === false && i == doc.sel.primIndex) continue; - var range = doc.sel.ranges[i]; - var collapsed = range.empty(); - if (collapsed || cm.options.showCursorWhenSelecting) - drawSelectionCursor(cm, range.head, curFragment); - if (!collapsed) - drawSelectionRange(cm, range, selFragment); - } - return result; - } - - // Draws a cursor for the given range - function drawSelectionCursor(cm, head, output) { - var pos = cursorCoords(cm, head, "div", null, null, !cm.options.singleCursorHeightPerLine); - - var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor")); - cursor.style.left = pos.left + "px"; - cursor.style.top = pos.top + "px"; - cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px"; - - if (pos.other) { - // Secondary cursor, shown when on a 'jump' in bi-directional text - var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor")); - otherCursor.style.display = ""; - otherCursor.style.left = pos.other.left + "px"; - otherCursor.style.top = pos.other.top + "px"; - otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px"; - } - } - - // Draws the given range as a highlighted selection - function drawSelectionRange(cm, range, output) { - var display = cm.display, doc = cm.doc; - var fragment = document.createDocumentFragment(); - var padding = paddingH(cm.display), leftSide = padding.left; - var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right; - - function add(left, top, width, bottom) { - if (top < 0) top = 0; - top = Math.round(top); - bottom = Math.round(bottom); - fragment.appendChild(elt("div", null, "CodeMirror-selected", "position: absolute; left: " + left + - "px; top: " + top + "px; width: " + (width == null ? rightSide - left : width) + - "px; height: " + (bottom - top) + "px")); - } - - function drawForLine(line, fromArg, toArg) { - var lineObj = getLine(doc, line); - var lineLen = lineObj.text.length; - var start, end; - function coords(ch, bias) { - return charCoords(cm, Pos(line, ch), "div", lineObj, bias); - } - - iterateBidiSections(getOrder(lineObj), fromArg || 0, toArg == null ? lineLen : toArg, function(from, to, dir) { - var leftPos = coords(from, "left"), rightPos, left, right; - if (from == to) { - rightPos = leftPos; - left = right = leftPos.left; - } else { - rightPos = coords(to - 1, "right"); - if (dir == "rtl") { var tmp = leftPos; leftPos = rightPos; rightPos = tmp; } - left = leftPos.left; - right = rightPos.right; - } - if (fromArg == null && from == 0) left = leftSide; - if (rightPos.top - leftPos.top > 3) { // Different lines, draw top part - add(left, leftPos.top, null, leftPos.bottom); - left = leftSide; - if (leftPos.bottom < rightPos.top) add(left, leftPos.bottom, null, rightPos.top); - } - if (toArg == null && to == lineLen) right = rightSide; - if (!start || leftPos.top < start.top || leftPos.top == start.top && leftPos.left < start.left) - start = leftPos; - if (!end || rightPos.bottom > end.bottom || rightPos.bottom == end.bottom && rightPos.right > end.right) - end = rightPos; - if (left < leftSide + 1) left = leftSide; - add(left, rightPos.top, right - left, rightPos.bottom); - }); - return {start: start, end: end}; - } - - var sFrom = range.from(), sTo = range.to(); - if (sFrom.line == sTo.line) { - drawForLine(sFrom.line, sFrom.ch, sTo.ch); - } else { - var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line); - var singleVLine = visualLine(fromLine) == visualLine(toLine); - var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end; - var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start; - if (singleVLine) { - if (leftEnd.top < rightStart.top - 2) { - add(leftEnd.right, leftEnd.top, null, leftEnd.bottom); - add(leftSide, rightStart.top, rightStart.left, rightStart.bottom); - } else { - add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom); - } - } - if (leftEnd.bottom < rightStart.top) - add(leftSide, leftEnd.bottom, null, rightStart.top); - } - - output.appendChild(fragment); - } - - // Cursor-blinking - function restartBlink(cm) { - if (!cm.state.focused) return; - var display = cm.display; - clearInterval(display.blinker); - var on = true; - display.cursorDiv.style.visibility = ""; - if (cm.options.cursorBlinkRate > 0) - display.blinker = setInterval(function() { - display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden"; - }, cm.options.cursorBlinkRate); - else if (cm.options.cursorBlinkRate < 0) - display.cursorDiv.style.visibility = "hidden"; - } - - // HIGHLIGHT WORKER - - function startWorker(cm, time) { - if (cm.doc.mode.startState && cm.doc.frontier < cm.display.viewTo) - cm.state.highlight.set(time, bind(highlightWorker, cm)); - } - - function highlightWorker(cm) { - var doc = cm.doc; - if (doc.frontier < doc.first) doc.frontier = doc.first; - if (doc.frontier >= cm.display.viewTo) return; - var end = +new Date + cm.options.workTime; - var state = copyState(doc.mode, getStateBefore(cm, doc.frontier)); - var changedLines = []; - - doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function(line) { - if (doc.frontier >= cm.display.viewFrom) { // Visible - var oldStyles = line.styles, tooLong = line.text.length > cm.options.maxHighlightLength; - var highlighted = highlightLine(cm, line, tooLong ? copyState(doc.mode, state) : state, true); - line.styles = highlighted.styles; - var oldCls = line.styleClasses, newCls = highlighted.classes; - if (newCls) line.styleClasses = newCls; - else if (oldCls) line.styleClasses = null; - var ischange = !oldStyles || oldStyles.length != line.styles.length || - oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass); - for (var i = 0; !ischange && i < oldStyles.length; ++i) ischange = oldStyles[i] != line.styles[i]; - if (ischange) changedLines.push(doc.frontier); - line.stateAfter = tooLong ? state : copyState(doc.mode, state); - } else { - if (line.text.length <= cm.options.maxHighlightLength) - processLine(cm, line.text, state); - line.stateAfter = doc.frontier % 5 == 0 ? copyState(doc.mode, state) : null; - } - ++doc.frontier; - if (+new Date > end) { - startWorker(cm, cm.options.workDelay); - return true; - } - }); - if (changedLines.length) runInOp(cm, function() { - for (var i = 0; i < changedLines.length; i++) - regLineChange(cm, changedLines[i], "text"); - }); - } - - // Finds the line to start with when starting a parse. Tries to - // find a line with a stateAfter, so that it can start with a - // valid state. If that fails, it returns the line with the - // smallest indentation, which tends to need the least context to - // parse correctly. - function findStartLine(cm, n, precise) { - var minindent, minline, doc = cm.doc; - var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100); - for (var search = n; search > lim; --search) { - if (search <= doc.first) return doc.first; - var line = getLine(doc, search - 1); - if (line.stateAfter && (!precise || search <= doc.frontier)) return search; - var indented = countColumn(line.text, null, cm.options.tabSize); - if (minline == null || minindent > indented) { - minline = search - 1; - minindent = indented; - } - } - return minline; - } - - function getStateBefore(cm, n, precise) { - var doc = cm.doc, display = cm.display; - if (!doc.mode.startState) return true; - var pos = findStartLine(cm, n, precise), state = pos > doc.first && getLine(doc, pos-1).stateAfter; - if (!state) state = startState(doc.mode); - else state = copyState(doc.mode, state); - doc.iter(pos, n, function(line) { - processLine(cm, line.text, state); - var save = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo; - line.stateAfter = save ? copyState(doc.mode, state) : null; - ++pos; - }); - if (precise) doc.frontier = pos; - return state; - } - - // POSITION MEASUREMENT - - function paddingTop(display) {return display.lineSpace.offsetTop;} - function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight;} - function paddingH(display) { - if (display.cachedPaddingH) return display.cachedPaddingH; - var e = removeChildrenAndAdd(display.measure, elt("pre", "x")); - var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle; - var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)}; - if (!isNaN(data.left) && !isNaN(data.right)) display.cachedPaddingH = data; - return data; - } - - function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth; } - function displayWidth(cm) { - return cm.display.scroller.clientWidth - scrollGap(cm) - cm.display.barWidth; - } - function displayHeight(cm) { - return cm.display.scroller.clientHeight - scrollGap(cm) - cm.display.barHeight; - } - - // Ensure the lineView.wrapping.heights array is populated. This is - // an array of bottom offsets for the lines that make up a drawn - // line. When lineWrapping is on, there might be more than one - // height. - function ensureLineHeights(cm, lineView, rect) { - var wrapping = cm.options.lineWrapping; - var curWidth = wrapping && displayWidth(cm); - if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) { - var heights = lineView.measure.heights = []; - if (wrapping) { - lineView.measure.width = curWidth; - var rects = lineView.text.firstChild.getClientRects(); - for (var i = 0; i < rects.length - 1; i++) { - var cur = rects[i], next = rects[i + 1]; - if (Math.abs(cur.bottom - next.bottom) > 2) - heights.push((cur.bottom + next.top) / 2 - rect.top); - } - } - heights.push(rect.bottom - rect.top); - } - } - - // Find a line map (mapping character offsets to text nodes) and a - // measurement cache for the given line number. (A line view might - // contain multiple lines when collapsed ranges are present.) - function mapFromLineView(lineView, line, lineN) { - if (lineView.line == line) - return {map: lineView.measure.map, cache: lineView.measure.cache}; - for (var i = 0; i < lineView.rest.length; i++) - if (lineView.rest[i] == line) - return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]}; - for (var i = 0; i < lineView.rest.length; i++) - if (lineNo(lineView.rest[i]) > lineN) - return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i], before: true}; - } - - // Render a line into the hidden node display.externalMeasured. Used - // when measurement is needed for a line that's not in the viewport. - function updateExternalMeasurement(cm, line) { - line = visualLine(line); - var lineN = lineNo(line); - var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN); - view.lineN = lineN; - var built = view.built = buildLineContent(cm, view); - view.text = built.pre; - removeChildrenAndAdd(cm.display.lineMeasure, built.pre); - return view; - } - - // Get a {top, bottom, left, right} box (in line-local coordinates) - // for a given character. - function measureChar(cm, line, ch, bias) { - return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias); - } - - // Find a line view that corresponds to the given line number. - function findViewForLine(cm, lineN) { - if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo) - return cm.display.view[findViewIndex(cm, lineN)]; - var ext = cm.display.externalMeasured; - if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size) - return ext; - } - - // Measurement can be split in two steps, the set-up work that - // applies to the whole line, and the measurement of the actual - // character. Functions like coordsChar, that need to do a lot of - // measurements in a row, can thus ensure that the set-up work is - // only done once. - function prepareMeasureForLine(cm, line) { - var lineN = lineNo(line); - var view = findViewForLine(cm, lineN); - if (view && !view.text) { - view = null; - } else if (view && view.changes) { - updateLineForChanges(cm, view, lineN, getDimensions(cm)); - cm.curOp.forceUpdate = true; - } - if (!view) - view = updateExternalMeasurement(cm, line); - - var info = mapFromLineView(view, line, lineN); - return { - line: line, view: view, rect: null, - map: info.map, cache: info.cache, before: info.before, - hasHeights: false - }; - } - - // Given a prepared measurement object, measures the position of an - // actual character (or fetches it from the cache). - function measureCharPrepared(cm, prepared, ch, bias, varHeight) { - if (prepared.before) ch = -1; - var key = ch + (bias || ""), found; - if (prepared.cache.hasOwnProperty(key)) { - found = prepared.cache[key]; - } else { - if (!prepared.rect) - prepared.rect = prepared.view.text.getBoundingClientRect(); - if (!prepared.hasHeights) { - ensureLineHeights(cm, prepared.view, prepared.rect); - prepared.hasHeights = true; - } - found = measureCharInner(cm, prepared, ch, bias); - if (!found.bogus) prepared.cache[key] = found; - } - return {left: found.left, right: found.right, - top: varHeight ? found.rtop : found.top, - bottom: varHeight ? found.rbottom : found.bottom}; - } - - var nullRect = {left: 0, right: 0, top: 0, bottom: 0}; - - function nodeAndOffsetInLineMap(map, ch, bias) { - var node, start, end, collapse; - // First, search the line map for the text node corresponding to, - // or closest to, the target character. - for (var i = 0; i < map.length; i += 3) { - var mStart = map[i], mEnd = map[i + 1]; - if (ch < mStart) { - start = 0; end = 1; - collapse = "left"; - } else if (ch < mEnd) { - start = ch - mStart; - end = start + 1; - } else if (i == map.length - 3 || ch == mEnd && map[i + 3] > ch) { - end = mEnd - mStart; - start = end - 1; - if (ch >= mEnd) collapse = "right"; - } - if (start != null) { - node = map[i + 2]; - if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right")) - collapse = bias; - if (bias == "left" && start == 0) - while (i && map[i - 2] == map[i - 3] && map[i - 1].insertLeft) { - node = map[(i -= 3) + 2]; - collapse = "left"; - } - if (bias == "right" && start == mEnd - mStart) - while (i < map.length - 3 && map[i + 3] == map[i + 4] && !map[i + 5].insertLeft) { - node = map[(i += 3) + 2]; - collapse = "right"; - } - break; - } - } - return {node: node, start: start, end: end, collapse: collapse, coverStart: mStart, coverEnd: mEnd}; - } - - function measureCharInner(cm, prepared, ch, bias) { - var place = nodeAndOffsetInLineMap(prepared.map, ch, bias); - var node = place.node, start = place.start, end = place.end, collapse = place.collapse; - - var rect; - if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates. - for (var i = 0; i < 4; i++) { // Retry a maximum of 4 times when nonsense rectangles are returned - while (start && isExtendingChar(prepared.line.text.charAt(place.coverStart + start))) --start; - while (place.coverStart + end < place.coverEnd && isExtendingChar(prepared.line.text.charAt(place.coverStart + end))) ++end; - if (ie && ie_version < 9 && start == 0 && end == place.coverEnd - place.coverStart) { - rect = node.parentNode.getBoundingClientRect(); - } else if (ie && cm.options.lineWrapping) { - var rects = range(node, start, end).getClientRects(); - if (rects.length) - rect = rects[bias == "right" ? rects.length - 1 : 0]; - else - rect = nullRect; - } else { - rect = range(node, start, end).getBoundingClientRect() || nullRect; - } - if (rect.left || rect.right || start == 0) break; - end = start; - start = start - 1; - collapse = "right"; - } - if (ie && ie_version < 11) rect = maybeUpdateRectForZooming(cm.display.measure, rect); - } else { // If it is a widget, simply get the box for the whole widget. - if (start > 0) collapse = bias = "right"; - var rects; - if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1) - rect = rects[bias == "right" ? rects.length - 1 : 0]; - else - rect = node.getBoundingClientRect(); - } - if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) { - var rSpan = node.parentNode.getClientRects()[0]; - if (rSpan) - rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom}; - else - rect = nullRect; - } - - var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top; - var mid = (rtop + rbot) / 2; - var heights = prepared.view.measure.heights; - for (var i = 0; i < heights.length - 1; i++) - if (mid < heights[i]) break; - var top = i ? heights[i - 1] : 0, bot = heights[i]; - var result = {left: (collapse == "right" ? rect.right : rect.left) - prepared.rect.left, - right: (collapse == "left" ? rect.left : rect.right) - prepared.rect.left, - top: top, bottom: bot}; - if (!rect.left && !rect.right) result.bogus = true; - if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot; } - - return result; - } - - // Work around problem with bounding client rects on ranges being - // returned incorrectly when zoomed on IE10 and below. - function maybeUpdateRectForZooming(measure, rect) { - if (!window.screen || screen.logicalXDPI == null || - screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure)) - return rect; - var scaleX = screen.logicalXDPI / screen.deviceXDPI; - var scaleY = screen.logicalYDPI / screen.deviceYDPI; - return {left: rect.left * scaleX, right: rect.right * scaleX, - top: rect.top * scaleY, bottom: rect.bottom * scaleY}; - } - - function clearLineMeasurementCacheFor(lineView) { - if (lineView.measure) { - lineView.measure.cache = {}; - lineView.measure.heights = null; - if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++) - lineView.measure.caches[i] = {}; - } - } - - function clearLineMeasurementCache(cm) { - cm.display.externalMeasure = null; - removeChildren(cm.display.lineMeasure); - for (var i = 0; i < cm.display.view.length; i++) - clearLineMeasurementCacheFor(cm.display.view[i]); - } - - function clearCaches(cm) { - clearLineMeasurementCache(cm); - cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null; - if (!cm.options.lineWrapping) cm.display.maxLineChanged = true; - cm.display.lineNumChars = null; - } - - function pageScrollX() { return window.pageXOffset || (document.documentElement || document.body).scrollLeft; } - function pageScrollY() { return window.pageYOffset || (document.documentElement || document.body).scrollTop; } - - // Converts a {top, bottom, left, right} box from line-local - // coordinates into another coordinate system. Context may be one of - // "line", "div" (display.lineDiv), "local"/null (editor), "window", - // or "page". - function intoCoordSystem(cm, lineObj, rect, context) { - if (lineObj.widgets) for (var i = 0; i < lineObj.widgets.length; ++i) if (lineObj.widgets[i].above) { - var size = widgetHeight(lineObj.widgets[i]); - rect.top += size; rect.bottom += size; - } - if (context == "line") return rect; - if (!context) context = "local"; - var yOff = heightAtLine(lineObj); - if (context == "local") yOff += paddingTop(cm.display); - else yOff -= cm.display.viewOffset; - if (context == "page" || context == "window") { - var lOff = cm.display.lineSpace.getBoundingClientRect(); - yOff += lOff.top + (context == "window" ? 0 : pageScrollY()); - var xOff = lOff.left + (context == "window" ? 0 : pageScrollX()); - rect.left += xOff; rect.right += xOff; - } - rect.top += yOff; rect.bottom += yOff; - return rect; - } - - // Coverts a box from "div" coords to another coordinate system. - // Context may be "window", "page", "div", or "local"/null. - function fromCoordSystem(cm, coords, context) { - if (context == "div") return coords; - var left = coords.left, top = coords.top; - // First move into "page" coordinate system - if (context == "page") { - left -= pageScrollX(); - top -= pageScrollY(); - } else if (context == "local" || !context) { - var localBox = cm.display.sizer.getBoundingClientRect(); - left += localBox.left; - top += localBox.top; - } - - var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect(); - return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top}; - } - - function charCoords(cm, pos, context, lineObj, bias) { - if (!lineObj) lineObj = getLine(cm.doc, pos.line); - return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context); - } - - // Returns a box for a given cursor position, which may have an - // 'other' property containing the position of the secondary cursor - // on a bidi boundary. - function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) { - lineObj = lineObj || getLine(cm.doc, pos.line); - if (!preparedMeasure) preparedMeasure = prepareMeasureForLine(cm, lineObj); - function get(ch, right) { - var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "left", varHeight); - if (right) m.left = m.right; else m.right = m.left; - return intoCoordSystem(cm, lineObj, m, context); - } - function getBidi(ch, partPos) { - var part = order[partPos], right = part.level % 2; - if (ch == bidiLeft(part) && partPos && part.level < order[partPos - 1].level) { - part = order[--partPos]; - ch = bidiRight(part) - (part.level % 2 ? 0 : 1); - right = true; - } else if (ch == bidiRight(part) && partPos < order.length - 1 && part.level < order[partPos + 1].level) { - part = order[++partPos]; - ch = bidiLeft(part) - part.level % 2; - right = false; - } - if (right && ch == part.to && ch > part.from) return get(ch - 1); - return get(ch, right); - } - var order = getOrder(lineObj), ch = pos.ch; - if (!order) return get(ch); - var partPos = getBidiPartAt(order, ch); - var val = getBidi(ch, partPos); - if (bidiOther != null) val.other = getBidi(ch, bidiOther); - return val; - } - - // Used to cheaply estimate the coordinates for a position. Used for - // intermediate scroll updates. - function estimateCoords(cm, pos) { - var left = 0, pos = clipPos(cm.doc, pos); - if (!cm.options.lineWrapping) left = charWidth(cm.display) * pos.ch; - var lineObj = getLine(cm.doc, pos.line); - var top = heightAtLine(lineObj) + paddingTop(cm.display); - return {left: left, right: left, top: top, bottom: top + lineObj.height}; - } - - // Positions returned by coordsChar contain some extra information. - // xRel is the relative x position of the input coordinates compared - // to the found position (so xRel > 0 means the coordinates are to - // the right of the character position, for example). When outside - // is true, that means the coordinates lie outside the line's - // vertical range. - function PosWithInfo(line, ch, outside, xRel) { - var pos = Pos(line, ch); - pos.xRel = xRel; - if (outside) pos.outside = true; - return pos; - } - - // Compute the character position closest to the given coordinates. - // Input must be lineSpace-local ("div" coordinate system). - function coordsChar(cm, x, y) { - var doc = cm.doc; - y += cm.display.viewOffset; - if (y < 0) return PosWithInfo(doc.first, 0, true, -1); - var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1; - if (lineN > last) - return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, true, 1); - if (x < 0) x = 0; - - var lineObj = getLine(doc, lineN); - for (;;) { - var found = coordsCharInner(cm, lineObj, lineN, x, y); - var merged = collapsedSpanAtEnd(lineObj); - var mergedPos = merged && merged.find(0, true); - if (merged && (found.ch > mergedPos.from.ch || found.ch == mergedPos.from.ch && found.xRel > 0)) - lineN = lineNo(lineObj = mergedPos.to.line); - else - return found; - } - } - - function coordsCharInner(cm, lineObj, lineNo, x, y) { - var innerOff = y - heightAtLine(lineObj); - var wrongLine = false, adjust = 2 * cm.display.wrapper.clientWidth; - var preparedMeasure = prepareMeasureForLine(cm, lineObj); - - function getX(ch) { - var sp = cursorCoords(cm, Pos(lineNo, ch), "line", lineObj, preparedMeasure); - wrongLine = true; - if (innerOff > sp.bottom) return sp.left - adjust; - else if (innerOff < sp.top) return sp.left + adjust; - else wrongLine = false; - return sp.left; - } - - var bidi = getOrder(lineObj), dist = lineObj.text.length; - var from = lineLeft(lineObj), to = lineRight(lineObj); - var fromX = getX(from), fromOutside = wrongLine, toX = getX(to), toOutside = wrongLine; - - if (x > toX) return PosWithInfo(lineNo, to, toOutside, 1); - // Do a binary search between these bounds. - for (;;) { - if (bidi ? to == from || to == moveVisually(lineObj, from, 1) : to - from <= 1) { - var ch = x < fromX || x - fromX <= toX - x ? from : to; - var xDiff = x - (ch == from ? fromX : toX); - while (isExtendingChar(lineObj.text.charAt(ch))) ++ch; - var pos = PosWithInfo(lineNo, ch, ch == from ? fromOutside : toOutside, - xDiff < -1 ? -1 : xDiff > 1 ? 1 : 0); - return pos; - } - var step = Math.ceil(dist / 2), middle = from + step; - if (bidi) { - middle = from; - for (var i = 0; i < step; ++i) middle = moveVisually(lineObj, middle, 1); - } - var middleX = getX(middle); - if (middleX > x) {to = middle; toX = middleX; if (toOutside = wrongLine) toX += 1000; dist = step;} - else {from = middle; fromX = middleX; fromOutside = wrongLine; dist -= step;} - } - } - - var measureText; - // Compute the default text height. - function textHeight(display) { - if (display.cachedTextHeight != null) return display.cachedTextHeight; - if (measureText == null) { - measureText = elt("pre"); - // Measure a bunch of lines, for browsers that compute - // fractional heights. - for (var i = 0; i < 49; ++i) { - measureText.appendChild(document.createTextNode("x")); - measureText.appendChild(elt("br")); - } - measureText.appendChild(document.createTextNode("x")); - } - removeChildrenAndAdd(display.measure, measureText); - var height = measureText.offsetHeight / 50; - if (height > 3) display.cachedTextHeight = height; - removeChildren(display.measure); - return height || 1; - } - - // Compute the default character width. - function charWidth(display) { - if (display.cachedCharWidth != null) return display.cachedCharWidth; - var anchor = elt("span", "xxxxxxxxxx"); - var pre = elt("pre", [anchor]); - removeChildrenAndAdd(display.measure, pre); - var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10; - if (width > 2) display.cachedCharWidth = width; - return width || 10; - } - - // OPERATIONS - - // Operations are used to wrap a series of changes to the editor - // state in such a way that each change won't have to update the - // cursor and display (which would be awkward, slow, and - // error-prone). Instead, display updates are batched and then all - // combined and executed at once. - - var operationGroup = null; - - var nextOpId = 0; - // Start a new operation. - function startOperation(cm) { - cm.curOp = { - cm: cm, - viewChanged: false, // Flag that indicates that lines might need to be redrawn - startHeight: cm.doc.height, // Used to detect need to update scrollbar - forceUpdate: false, // Used to force a redraw - updateInput: null, // Whether to reset the input textarea - typing: false, // Whether this reset should be careful to leave existing text (for compositing) - changeObjs: null, // Accumulated changes, for firing change events - cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on - cursorActivityCalled: 0, // Tracks which cursorActivity handlers have been called already - selectionChanged: false, // Whether the selection needs to be redrawn - updateMaxLine: false, // Set when the widest line needs to be determined anew - scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet - scrollToPos: null, // Used to scroll to a specific position - focus: false, - id: ++nextOpId // Unique ID - }; - if (operationGroup) { - operationGroup.ops.push(cm.curOp); - } else { - cm.curOp.ownsGroup = operationGroup = { - ops: [cm.curOp], - delayedCallbacks: [] - }; - } - } - - function fireCallbacksForOps(group) { - // Calls delayed callbacks and cursorActivity handlers until no - // new ones appear - var callbacks = group.delayedCallbacks, i = 0; - do { - for (; i < callbacks.length; i++) - callbacks[i].call(null); - for (var j = 0; j < group.ops.length; j++) { - var op = group.ops[j]; - if (op.cursorActivityHandlers) - while (op.cursorActivityCalled < op.cursorActivityHandlers.length) - op.cursorActivityHandlers[op.cursorActivityCalled++].call(null, op.cm); - } - } while (i < callbacks.length); - } - - // Finish an operation, updating the display and signalling delayed events - function endOperation(cm) { - var op = cm.curOp, group = op.ownsGroup; - if (!group) return; - - try { fireCallbacksForOps(group); } - finally { - operationGroup = null; - for (var i = 0; i < group.ops.length; i++) - group.ops[i].cm.curOp = null; - endOperations(group); - } - } - - // The DOM updates done when an operation finishes are batched so - // that the minimum number of relayouts are required. - function endOperations(group) { - var ops = group.ops; - for (var i = 0; i < ops.length; i++) // Read DOM - endOperation_R1(ops[i]); - for (var i = 0; i < ops.length; i++) // Write DOM (maybe) - endOperation_W1(ops[i]); - for (var i = 0; i < ops.length; i++) // Read DOM - endOperation_R2(ops[i]); - for (var i = 0; i < ops.length; i++) // Write DOM (maybe) - endOperation_W2(ops[i]); - for (var i = 0; i < ops.length; i++) // Read DOM - endOperation_finish(ops[i]); - } - - function endOperation_R1(op) { - var cm = op.cm, display = cm.display; - maybeClipScrollbars(cm); - if (op.updateMaxLine) findMaxLine(cm); - - op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null || - op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom || - op.scrollToPos.to.line >= display.viewTo) || - display.maxLineChanged && cm.options.lineWrapping; - op.update = op.mustUpdate && - new DisplayUpdate(cm, op.mustUpdate && {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate); - } - - function endOperation_W1(op) { - op.updatedDisplay = op.mustUpdate && updateDisplayIfNeeded(op.cm, op.update); - } - - function endOperation_R2(op) { - var cm = op.cm, display = cm.display; - if (op.updatedDisplay) updateHeightsInViewport(cm); - - op.barMeasure = measureForScrollbars(cm); - - // If the max line changed since it was last measured, measure it, - // and ensure the document's width matches it. - // updateDisplay_W2 will use these properties to do the actual resizing - if (display.maxLineChanged && !cm.options.lineWrapping) { - op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3; - cm.display.sizerWidth = op.adjustWidthTo; - op.barMeasure.scrollWidth = - Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth); - op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm)); - } - - if (op.updatedDisplay || op.selectionChanged) - op.preparedSelection = display.input.prepareSelection(); - } - - function endOperation_W2(op) { - var cm = op.cm; - - if (op.adjustWidthTo != null) { - cm.display.sizer.style.minWidth = op.adjustWidthTo + "px"; - if (op.maxScrollLeft < cm.doc.scrollLeft) - setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true); - cm.display.maxLineChanged = false; - } - - if (op.preparedSelection) - cm.display.input.showSelection(op.preparedSelection); - if (op.updatedDisplay) - setDocumentHeight(cm, op.barMeasure); - if (op.updatedDisplay || op.startHeight != cm.doc.height) - updateScrollbars(cm, op.barMeasure); - - if (op.selectionChanged) restartBlink(cm); - - if (cm.state.focused && op.updateInput) - cm.display.input.reset(op.typing); - if (op.focus && op.focus == activeElt() && (!document.hasFocus || document.hasFocus())) - ensureFocus(op.cm); - } - - function endOperation_finish(op) { - var cm = op.cm, display = cm.display, doc = cm.doc; - - if (op.updatedDisplay) postUpdateDisplay(cm, op.update); - - // Abort mouse wheel delta measurement, when scrolling explicitly - if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos)) - display.wheelStartX = display.wheelStartY = null; - - // Propagate the scroll position to the actual DOM scroller - if (op.scrollTop != null && (display.scroller.scrollTop != op.scrollTop || op.forceScroll)) { - doc.scrollTop = Math.max(0, Math.min(display.scroller.scrollHeight - display.scroller.clientHeight, op.scrollTop)); - display.scrollbars.setScrollTop(doc.scrollTop); - display.scroller.scrollTop = doc.scrollTop; - } - if (op.scrollLeft != null && (display.scroller.scrollLeft != op.scrollLeft || op.forceScroll)) { - doc.scrollLeft = Math.max(0, Math.min(display.scroller.scrollWidth - display.scroller.clientWidth, op.scrollLeft)); - display.scrollbars.setScrollLeft(doc.scrollLeft); - display.scroller.scrollLeft = doc.scrollLeft; - alignHorizontally(cm); - } - // If we need to scroll a specific position into view, do so. - if (op.scrollToPos) { - var coords = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from), - clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin); - if (op.scrollToPos.isCursor && cm.state.focused) maybeScrollWindow(cm, coords); - } - - // Fire events for markers that are hidden/unidden by editing or - // undoing - var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers; - if (hidden) for (var i = 0; i < hidden.length; ++i) - if (!hidden[i].lines.length) signal(hidden[i], "hide"); - if (unhidden) for (var i = 0; i < unhidden.length; ++i) - if (unhidden[i].lines.length) signal(unhidden[i], "unhide"); - - if (display.wrapper.offsetHeight) - doc.scrollTop = cm.display.scroller.scrollTop; - - // Fire change events, and delayed event handlers - if (op.changeObjs) - signal(cm, "changes", cm, op.changeObjs); - if (op.update) - op.update.finish(); - } - - // Run the given function in an operation - function runInOp(cm, f) { - if (cm.curOp) return f(); - startOperation(cm); - try { return f(); } - finally { endOperation(cm); } - } - // Wraps a function in an operation. Returns the wrapped function. - function operation(cm, f) { - return function() { - if (cm.curOp) return f.apply(cm, arguments); - startOperation(cm); - try { return f.apply(cm, arguments); } - finally { endOperation(cm); } - }; - } - // Used to add methods to editor and doc instances, wrapping them in - // operations. - function methodOp(f) { - return function() { - if (this.curOp) return f.apply(this, arguments); - startOperation(this); - try { return f.apply(this, arguments); } - finally { endOperation(this); } - }; - } - function docMethodOp(f) { - return function() { - var cm = this.cm; - if (!cm || cm.curOp) return f.apply(this, arguments); - startOperation(cm); - try { return f.apply(this, arguments); } - finally { endOperation(cm); } - }; - } - - // VIEW TRACKING - - // These objects are used to represent the visible (currently drawn) - // part of the document. A LineView may correspond to multiple - // logical lines, if those are connected by collapsed ranges. - function LineView(doc, line, lineN) { - // The starting line - this.line = line; - // Continuing lines, if any - this.rest = visualLineContinued(line); - // Number of logical lines in this visual line - this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1; - this.node = this.text = null; - this.hidden = lineIsHidden(doc, line); - } - - // Create a range of LineView objects for the given lines. - function buildViewArray(cm, from, to) { - var array = [], nextPos; - for (var pos = from; pos < to; pos = nextPos) { - var view = new LineView(cm.doc, getLine(cm.doc, pos), pos); - nextPos = pos + view.size; - array.push(view); - } - return array; - } - - // Updates the display.view data structure for a given change to the - // document. From and to are in pre-change coordinates. Lendiff is - // the amount of lines added or subtracted by the change. This is - // used for changes that span multiple lines, or change the way - // lines are divided into visual lines. regLineChange (below) - // registers single-line changes. - function regChange(cm, from, to, lendiff) { - if (from == null) from = cm.doc.first; - if (to == null) to = cm.doc.first + cm.doc.size; - if (!lendiff) lendiff = 0; - - var display = cm.display; - if (lendiff && to < display.viewTo && - (display.updateLineNumbers == null || display.updateLineNumbers > from)) - display.updateLineNumbers = from; - - cm.curOp.viewChanged = true; - - if (from >= display.viewTo) { // Change after - if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo) - resetView(cm); - } else if (to <= display.viewFrom) { // Change before - if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) { - resetView(cm); - } else { - display.viewFrom += lendiff; - display.viewTo += lendiff; - } - } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap - resetView(cm); - } else if (from <= display.viewFrom) { // Top overlap - var cut = viewCuttingPoint(cm, to, to + lendiff, 1); - if (cut) { - display.view = display.view.slice(cut.index); - display.viewFrom = cut.lineN; - display.viewTo += lendiff; - } else { - resetView(cm); - } - } else if (to >= display.viewTo) { // Bottom overlap - var cut = viewCuttingPoint(cm, from, from, -1); - if (cut) { - display.view = display.view.slice(0, cut.index); - display.viewTo = cut.lineN; - } else { - resetView(cm); - } - } else { // Gap in the middle - var cutTop = viewCuttingPoint(cm, from, from, -1); - var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1); - if (cutTop && cutBot) { - display.view = display.view.slice(0, cutTop.index) - .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN)) - .concat(display.view.slice(cutBot.index)); - display.viewTo += lendiff; - } else { - resetView(cm); - } - } - - var ext = display.externalMeasured; - if (ext) { - if (to < ext.lineN) - ext.lineN += lendiff; - else if (from < ext.lineN + ext.size) - display.externalMeasured = null; - } - } - - // Register a change to a single line. Type must be one of "text", - // "gutter", "class", "widget" - function regLineChange(cm, line, type) { - cm.curOp.viewChanged = true; - var display = cm.display, ext = cm.display.externalMeasured; - if (ext && line >= ext.lineN && line < ext.lineN + ext.size) - display.externalMeasured = null; - - if (line < display.viewFrom || line >= display.viewTo) return; - var lineView = display.view[findViewIndex(cm, line)]; - if (lineView.node == null) return; - var arr = lineView.changes || (lineView.changes = []); - if (indexOf(arr, type) == -1) arr.push(type); - } - - // Clear the view. - function resetView(cm) { - cm.display.viewFrom = cm.display.viewTo = cm.doc.first; - cm.display.view = []; - cm.display.viewOffset = 0; - } - - // Find the view element corresponding to a given line. Return null - // when the line isn't visible. - function findViewIndex(cm, n) { - if (n >= cm.display.viewTo) return null; - n -= cm.display.viewFrom; - if (n < 0) return null; - var view = cm.display.view; - for (var i = 0; i < view.length; i++) { - n -= view[i].size; - if (n < 0) return i; - } - } - - function viewCuttingPoint(cm, oldN, newN, dir) { - var index = findViewIndex(cm, oldN), diff, view = cm.display.view; - if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size) - return {index: index, lineN: newN}; - for (var i = 0, n = cm.display.viewFrom; i < index; i++) - n += view[i].size; - if (n != oldN) { - if (dir > 0) { - if (index == view.length - 1) return null; - diff = (n + view[index].size) - oldN; - index++; - } else { - diff = n - oldN; - } - oldN += diff; newN += diff; - } - while (visualLineNo(cm.doc, newN) != newN) { - if (index == (dir < 0 ? 0 : view.length - 1)) return null; - newN += dir * view[index - (dir < 0 ? 1 : 0)].size; - index += dir; - } - return {index: index, lineN: newN}; - } - - // Force the view to cover a given range, adding empty view element - // or clipping off existing ones as needed. - function adjustView(cm, from, to) { - var display = cm.display, view = display.view; - if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) { - display.view = buildViewArray(cm, from, to); - display.viewFrom = from; - } else { - if (display.viewFrom > from) - display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view); - else if (display.viewFrom < from) - display.view = display.view.slice(findViewIndex(cm, from)); - display.viewFrom = from; - if (display.viewTo < to) - display.view = display.view.concat(buildViewArray(cm, display.viewTo, to)); - else if (display.viewTo > to) - display.view = display.view.slice(0, findViewIndex(cm, to)); - } - display.viewTo = to; - } - - // Count the number of lines in the view whose DOM representation is - // out of date (or nonexistent). - function countDirtyView(cm) { - var view = cm.display.view, dirty = 0; - for (var i = 0; i < view.length; i++) { - var lineView = view[i]; - if (!lineView.hidden && (!lineView.node || lineView.changes)) ++dirty; - } - return dirty; - } - - // EVENT HANDLERS - - // Attach the necessary event handlers when initializing the editor - function registerEventHandlers(cm) { - var d = cm.display; - on(d.scroller, "mousedown", operation(cm, onMouseDown)); - // Older IE's will not fire a second mousedown for a double click - if (ie && ie_version < 11) - on(d.scroller, "dblclick", operation(cm, function(e) { - if (signalDOMEvent(cm, e)) return; - var pos = posFromMouse(cm, e); - if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) return; - e_preventDefault(e); - var word = cm.findWordAt(pos); - extendSelection(cm.doc, word.anchor, word.head); - })); - else - on(d.scroller, "dblclick", function(e) { signalDOMEvent(cm, e) || e_preventDefault(e); }); - // Some browsers fire contextmenu *after* opening the menu, at - // which point we can't mess with it anymore. Context menu is - // handled in onMouseDown for these browsers. - if (!captureRightClick) on(d.scroller, "contextmenu", function(e) {onContextMenu(cm, e);}); - - // Used to suppress mouse event handling when a touch happens - var touchFinished, prevTouch = {end: 0}; - function finishTouch() { - if (d.activeTouch) { - touchFinished = setTimeout(function() {d.activeTouch = null;}, 1000); - prevTouch = d.activeTouch; - prevTouch.end = +new Date; - } - }; - function isMouseLikeTouchEvent(e) { - if (e.touches.length != 1) return false; - var touch = e.touches[0]; - return touch.radiusX <= 1 && touch.radiusY <= 1; - } - function farAway(touch, other) { - if (other.left == null) return true; - var dx = other.left - touch.left, dy = other.top - touch.top; - return dx * dx + dy * dy > 20 * 20; - } - on(d.scroller, "touchstart", function(e) { - if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e)) { - clearTimeout(touchFinished); - var now = +new Date; - d.activeTouch = {start: now, moved: false, - prev: now - prevTouch.end <= 300 ? prevTouch : null}; - if (e.touches.length == 1) { - d.activeTouch.left = e.touches[0].pageX; - d.activeTouch.top = e.touches[0].pageY; - } - } - }); - on(d.scroller, "touchmove", function() { - if (d.activeTouch) d.activeTouch.moved = true; - }); - on(d.scroller, "touchend", function(e) { - var touch = d.activeTouch; - if (touch && !eventInWidget(d, e) && touch.left != null && - !touch.moved && new Date - touch.start < 300) { - var pos = cm.coordsChar(d.activeTouch, "page"), range; - if (!touch.prev || farAway(touch, touch.prev)) // Single tap - range = new Range(pos, pos); - else if (!touch.prev.prev || farAway(touch, touch.prev.prev)) // Double tap - range = cm.findWordAt(pos); - else // Triple tap - range = new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))); - cm.setSelection(range.anchor, range.head); - cm.focus(); - e_preventDefault(e); - } - finishTouch(); - }); - on(d.scroller, "touchcancel", finishTouch); - - // Sync scrolling between fake scrollbars and real scrollable - // area, ensure viewport is updated when scrolling. - on(d.scroller, "scroll", function() { - if (d.scroller.clientHeight) { - setScrollTop(cm, d.scroller.scrollTop); - setScrollLeft(cm, d.scroller.scrollLeft, true); - signal(cm, "scroll", cm); - } - }); - - // Listen to wheel events in order to try and update the viewport on time. - on(d.scroller, "mousewheel", function(e){onScrollWheel(cm, e);}); - on(d.scroller, "DOMMouseScroll", function(e){onScrollWheel(cm, e);}); - - // Prevent wrapper from ever scrolling - on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; }); - - d.dragFunctions = { - enter: function(e) {if (!signalDOMEvent(cm, e)) e_stop(e);}, - over: function(e) {if (!signalDOMEvent(cm, e)) { onDragOver(cm, e); e_stop(e); }}, - start: function(e){onDragStart(cm, e);}, - drop: operation(cm, onDrop), - leave: function() {clearDragCursor(cm);} - }; - - var inp = d.input.getField(); - on(inp, "keyup", function(e) { onKeyUp.call(cm, e); }); - on(inp, "keydown", operation(cm, onKeyDown)); - on(inp, "keypress", operation(cm, onKeyPress)); - on(inp, "focus", bind(onFocus, cm)); - on(inp, "blur", bind(onBlur, cm)); - } - - function dragDropChanged(cm, value, old) { - var wasOn = old && old != CodeMirror.Init; - if (!value != !wasOn) { - var funcs = cm.display.dragFunctions; - var toggle = value ? on : off; - toggle(cm.display.scroller, "dragstart", funcs.start); - toggle(cm.display.scroller, "dragenter", funcs.enter); - toggle(cm.display.scroller, "dragover", funcs.over); - toggle(cm.display.scroller, "dragleave", funcs.leave); - toggle(cm.display.scroller, "drop", funcs.drop); - } - } - - // Called when the window resizes - function onResize(cm) { - var d = cm.display; - if (d.lastWrapHeight == d.wrapper.clientHeight && d.lastWrapWidth == d.wrapper.clientWidth) - return; - // Might be a text scaling operation, clear size caches. - d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null; - d.scrollbarsClipped = false; - cm.setSize(); - } - - // MOUSE EVENTS - - // Return true when the given mouse event happened in a widget - function eventInWidget(display, e) { - for (var n = e_target(e); n != display.wrapper; n = n.parentNode) { - if (!n || (n.nodeType == 1 && n.getAttribute("cm-ignore-events") == "true") || - (n.parentNode == display.sizer && n != display.mover)) - return true; - } - } - - // Given a mouse event, find the corresponding position. If liberal - // is false, it checks whether a gutter or scrollbar was clicked, - // and returns null if it was. forRect is used by rectangular - // selections, and tries to estimate a character position even for - // coordinates beyond the right of the text. - function posFromMouse(cm, e, liberal, forRect) { - var display = cm.display; - if (!liberal && e_target(e).getAttribute("cm-not-content") == "true") return null; - - var x, y, space = display.lineSpace.getBoundingClientRect(); - // Fails unpredictably on IE[67] when mouse is dragged around quickly. - try { x = e.clientX - space.left; y = e.clientY - space.top; } - catch (e) { return null; } - var coords = coordsChar(cm, x, y), line; - if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) { - var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length; - coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff)); - } - return coords; - } - - // A mouse down can be a single click, double click, triple click, - // start of selection drag, start of text drag, new cursor - // (ctrl-click), rectangle drag (alt-drag), or xwin - // middle-click-paste. Or it might be a click on something we should - // not interfere with, such as a scrollbar or widget. - function onMouseDown(e) { - var cm = this, display = cm.display; - if (signalDOMEvent(cm, e) || display.activeTouch && display.input.supportsTouch()) return; - display.shift = e.shiftKey; - - if (eventInWidget(display, e)) { - if (!webkit) { - // Briefly turn off draggability, to allow widgets to do - // normal dragging things. - display.scroller.draggable = false; - setTimeout(function(){display.scroller.draggable = true;}, 100); - } - return; - } - if (clickInGutter(cm, e)) return; - var start = posFromMouse(cm, e); - window.focus(); - - switch (e_button(e)) { - case 1: - // #3261: make sure, that we're not starting a second selection - if (cm.state.selectingText) - cm.state.selectingText(e); - else if (start) - leftButtonDown(cm, e, start); - else if (e_target(e) == display.scroller) - e_preventDefault(e); - break; - case 2: - if (webkit) cm.state.lastMiddleDown = +new Date; - if (start) extendSelection(cm.doc, start); - setTimeout(function() {display.input.focus();}, 20); - e_preventDefault(e); - break; - case 3: - if (captureRightClick) onContextMenu(cm, e); - else delayBlurEvent(cm); - break; - } - } - - var lastClick, lastDoubleClick; - function leftButtonDown(cm, e, start) { - if (ie) setTimeout(bind(ensureFocus, cm), 0); - else cm.curOp.focus = activeElt(); - - var now = +new Date, type; - if (lastDoubleClick && lastDoubleClick.time > now - 400 && cmp(lastDoubleClick.pos, start) == 0) { - type = "triple"; - } else if (lastClick && lastClick.time > now - 400 && cmp(lastClick.pos, start) == 0) { - type = "double"; - lastDoubleClick = {time: now, pos: start}; - } else { - type = "single"; - lastClick = {time: now, pos: start}; - } - - var sel = cm.doc.sel, modifier = mac ? e.metaKey : e.ctrlKey, contained; - if (cm.options.dragDrop && dragAndDrop && !cm.isReadOnly() && - type == "single" && (contained = sel.contains(start)) > -1 && - (cmp((contained = sel.ranges[contained]).from(), start) < 0 || start.xRel > 0) && - (cmp(contained.to(), start) > 0 || start.xRel < 0)) - leftButtonStartDrag(cm, e, start, modifier); - else - leftButtonSelect(cm, e, start, type, modifier); - } - - // Start a text drag. When it ends, see if any dragging actually - // happen, and treat as a click if it didn't. - function leftButtonStartDrag(cm, e, start, modifier) { - var display = cm.display, startTime = +new Date; - var dragEnd = operation(cm, function(e2) { - if (webkit) display.scroller.draggable = false; - cm.state.draggingText = false; - off(document, "mouseup", dragEnd); - off(display.scroller, "drop", dragEnd); - if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) { - e_preventDefault(e2); - if (!modifier && +new Date - 200 < startTime) - extendSelection(cm.doc, start); - // Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081) - if (webkit || ie && ie_version == 9) - setTimeout(function() {document.body.focus(); display.input.focus();}, 20); - else - display.input.focus(); - } - }); - // Let the drag handler handle this. - if (webkit) display.scroller.draggable = true; - cm.state.draggingText = dragEnd; - // IE's approach to draggable - if (display.scroller.dragDrop) display.scroller.dragDrop(); - on(document, "mouseup", dragEnd); - on(display.scroller, "drop", dragEnd); - } - - // Normal selection, as opposed to text dragging. - function leftButtonSelect(cm, e, start, type, addNew) { - var display = cm.display, doc = cm.doc; - e_preventDefault(e); - - var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges; - if (addNew && !e.shiftKey) { - ourIndex = doc.sel.contains(start); - if (ourIndex > -1) - ourRange = ranges[ourIndex]; - else - ourRange = new Range(start, start); - } else { - ourRange = doc.sel.primary(); - ourIndex = doc.sel.primIndex; - } - - if (e.altKey) { - type = "rect"; - if (!addNew) ourRange = new Range(start, start); - start = posFromMouse(cm, e, true, true); - ourIndex = -1; - } else if (type == "double") { - var word = cm.findWordAt(start); - if (cm.display.shift || doc.extend) - ourRange = extendRange(doc, ourRange, word.anchor, word.head); - else - ourRange = word; - } else if (type == "triple") { - var line = new Range(Pos(start.line, 0), clipPos(doc, Pos(start.line + 1, 0))); - if (cm.display.shift || doc.extend) - ourRange = extendRange(doc, ourRange, line.anchor, line.head); - else - ourRange = line; - } else { - ourRange = extendRange(doc, ourRange, start); - } - - if (!addNew) { - ourIndex = 0; - setSelection(doc, new Selection([ourRange], 0), sel_mouse); - startSel = doc.sel; - } else if (ourIndex == -1) { - ourIndex = ranges.length; - setSelection(doc, normalizeSelection(ranges.concat([ourRange]), ourIndex), - {scroll: false, origin: "*mouse"}); - } else if (ranges.length > 1 && ranges[ourIndex].empty() && type == "single" && !e.shiftKey) { - setSelection(doc, normalizeSelection(ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0), - {scroll: false, origin: "*mouse"}); - startSel = doc.sel; - } else { - replaceOneSelection(doc, ourIndex, ourRange, sel_mouse); - } - - var lastPos = start; - function extendTo(pos) { - if (cmp(lastPos, pos) == 0) return; - lastPos = pos; - - if (type == "rect") { - var ranges = [], tabSize = cm.options.tabSize; - var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize); - var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize); - var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol); - for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line)); - line <= end; line++) { - var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize); - if (left == right) - ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos))); - else if (text.length > leftPos) - ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize)))); - } - if (!ranges.length) ranges.push(new Range(start, start)); - setSelection(doc, normalizeSelection(startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex), - {origin: "*mouse", scroll: false}); - cm.scrollIntoView(pos); - } else { - var oldRange = ourRange; - var anchor = oldRange.anchor, head = pos; - if (type != "single") { - if (type == "double") - var range = cm.findWordAt(pos); - else - var range = new Range(Pos(pos.line, 0), clipPos(doc, Pos(pos.line + 1, 0))); - if (cmp(range.anchor, anchor) > 0) { - head = range.head; - anchor = minPos(oldRange.from(), range.anchor); - } else { - head = range.anchor; - anchor = maxPos(oldRange.to(), range.head); - } - } - var ranges = startSel.ranges.slice(0); - ranges[ourIndex] = new Range(clipPos(doc, anchor), head); - setSelection(doc, normalizeSelection(ranges, ourIndex), sel_mouse); - } - } - - var editorSize = display.wrapper.getBoundingClientRect(); - // Used to ensure timeout re-tries don't fire when another extend - // happened in the meantime (clearTimeout isn't reliable -- at - // least on Chrome, the timeouts still happen even when cleared, - // if the clear happens after their scheduled firing time). - var counter = 0; - - function extend(e) { - var curCount = ++counter; - var cur = posFromMouse(cm, e, true, type == "rect"); - if (!cur) return; - if (cmp(cur, lastPos) != 0) { - cm.curOp.focus = activeElt(); - extendTo(cur); - var visible = visibleLines(display, doc); - if (cur.line >= visible.to || cur.line < visible.from) - setTimeout(operation(cm, function(){if (counter == curCount) extend(e);}), 150); - } else { - var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0; - if (outside) setTimeout(operation(cm, function() { - if (counter != curCount) return; - display.scroller.scrollTop += outside; - extend(e); - }), 50); - } - } - - function done(e) { - cm.state.selectingText = false; - counter = Infinity; - e_preventDefault(e); - display.input.focus(); - off(document, "mousemove", move); - off(document, "mouseup", up); - doc.history.lastSelOrigin = null; - } - - var move = operation(cm, function(e) { - if (!e_button(e)) done(e); - else extend(e); - }); - var up = operation(cm, done); - cm.state.selectingText = up; - on(document, "mousemove", move); - on(document, "mouseup", up); - } - - // Determines whether an event happened in the gutter, and fires the - // handlers for the corresponding event. - function gutterEvent(cm, e, type, prevent) { - try { var mX = e.clientX, mY = e.clientY; } - catch(e) { return false; } - if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) return false; - if (prevent) e_preventDefault(e); - - var display = cm.display; - var lineBox = display.lineDiv.getBoundingClientRect(); - - if (mY > lineBox.bottom || !hasHandler(cm, type)) return e_defaultPrevented(e); - mY -= lineBox.top - display.viewOffset; - - for (var i = 0; i < cm.options.gutters.length; ++i) { - var g = display.gutters.childNodes[i]; - if (g && g.getBoundingClientRect().right >= mX) { - var line = lineAtHeight(cm.doc, mY); - var gutter = cm.options.gutters[i]; - signal(cm, type, cm, line, gutter, e); - return e_defaultPrevented(e); - } - } - } - - function clickInGutter(cm, e) { - return gutterEvent(cm, e, "gutterClick", true); - } - - // Kludge to work around strange IE behavior where it'll sometimes - // re-fire a series of drag-related events right after the drop (#1551) - var lastDrop = 0; - - function onDrop(e) { - var cm = this; - clearDragCursor(cm); - if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) - return; - e_preventDefault(e); - if (ie) lastDrop = +new Date; - var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files; - if (!pos || cm.isReadOnly()) return; - // Might be a file drop, in which case we simply extract the text - // and insert it. - if (files && files.length && window.FileReader && window.File) { - var n = files.length, text = Array(n), read = 0; - var loadFile = function(file, i) { - if (cm.options.allowDropFileTypes && - indexOf(cm.options.allowDropFileTypes, file.type) == -1) - return; - - var reader = new FileReader; - reader.onload = operation(cm, function() { - var content = reader.result; - if (/[\x00-\x08\x0e-\x1f]{2}/.test(content)) content = ""; - text[i] = content; - if (++read == n) { - pos = clipPos(cm.doc, pos); - var change = {from: pos, to: pos, - text: cm.doc.splitLines(text.join(cm.doc.lineSeparator())), - origin: "paste"}; - makeChange(cm.doc, change); - setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change))); - } - }); - reader.readAsText(file); - }; - for (var i = 0; i < n; ++i) loadFile(files[i], i); - } else { // Normal drop - // Don't do a replace if the drop happened inside of the selected text. - if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) { - cm.state.draggingText(e); - // Ensure the editor is re-focused - setTimeout(function() {cm.display.input.focus();}, 20); - return; - } - try { - var text = e.dataTransfer.getData("Text"); - if (text) { - if (cm.state.draggingText && !(mac ? e.altKey : e.ctrlKey)) - var selected = cm.listSelections(); - setSelectionNoUndo(cm.doc, simpleSelection(pos, pos)); - if (selected) for (var i = 0; i < selected.length; ++i) - replaceRange(cm.doc, "", selected[i].anchor, selected[i].head, "drag"); - cm.replaceSelection(text, "around", "paste"); - cm.display.input.focus(); - } - } - catch(e){} - } - } - - function onDragStart(cm, e) { - if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return; } - if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) return; - - e.dataTransfer.setData("Text", cm.getSelection()); - - // Use dummy image instead of default browsers image. - // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there. - if (e.dataTransfer.setDragImage && !safari) { - var img = elt("img", null, null, "position: fixed; left: 0; top: 0;"); - img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="; - if (presto) { - img.width = img.height = 1; - cm.display.wrapper.appendChild(img); - // Force a relayout, or Opera won't use our image for some obscure reason - img._top = img.offsetTop; - } - e.dataTransfer.setDragImage(img, 0, 0); - if (presto) img.parentNode.removeChild(img); - } - } - - function onDragOver(cm, e) { - var pos = posFromMouse(cm, e); - if (!pos) return; - var frag = document.createDocumentFragment(); - drawSelectionCursor(cm, pos, frag); - if (!cm.display.dragCursor) { - cm.display.dragCursor = elt("div", null, "CodeMirror-cursors CodeMirror-dragcursors"); - cm.display.lineSpace.insertBefore(cm.display.dragCursor, cm.display.cursorDiv); - } - removeChildrenAndAdd(cm.display.dragCursor, frag); - } - - function clearDragCursor(cm) { - if (cm.display.dragCursor) { - cm.display.lineSpace.removeChild(cm.display.dragCursor); - cm.display.dragCursor = null; - } - } - - // SCROLL EVENTS - - // Sync the scrollable area and scrollbars, ensure the viewport - // covers the visible area. - function setScrollTop(cm, val) { - if (Math.abs(cm.doc.scrollTop - val) < 2) return; - cm.doc.scrollTop = val; - if (!gecko) updateDisplaySimple(cm, {top: val}); - if (cm.display.scroller.scrollTop != val) cm.display.scroller.scrollTop = val; - cm.display.scrollbars.setScrollTop(val); - if (gecko) updateDisplaySimple(cm); - startWorker(cm, 100); - } - // Sync scroller and scrollbar, ensure the gutter elements are - // aligned. - function setScrollLeft(cm, val, isScroller) { - if (isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) return; - val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth); - cm.doc.scrollLeft = val; - alignHorizontally(cm); - if (cm.display.scroller.scrollLeft != val) cm.display.scroller.scrollLeft = val; - cm.display.scrollbars.setScrollLeft(val); - } - - // Since the delta values reported on mouse wheel events are - // unstandardized between browsers and even browser versions, and - // generally horribly unpredictable, this code starts by measuring - // the scroll effect that the first few mouse wheel events have, - // and, from that, detects the way it can convert deltas to pixel - // offsets afterwards. - // - // The reason we want to know the amount a wheel event will scroll - // is that it gives us a chance to update the display before the - // actual scrolling happens, reducing flickering. - - var wheelSamples = 0, wheelPixelsPerUnit = null; - // Fill in a browser-detected starting value on browsers where we - // know one. These don't have to be accurate -- the result of them - // being wrong would just be a slight flicker on the first wheel - // scroll (if it is large enough). - if (ie) wheelPixelsPerUnit = -.53; - else if (gecko) wheelPixelsPerUnit = 15; - else if (chrome) wheelPixelsPerUnit = -.7; - else if (safari) wheelPixelsPerUnit = -1/3; - - var wheelEventDelta = function(e) { - var dx = e.wheelDeltaX, dy = e.wheelDeltaY; - if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) dx = e.detail; - if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) dy = e.detail; - else if (dy == null) dy = e.wheelDelta; - return {x: dx, y: dy}; - }; - CodeMirror.wheelEventPixels = function(e) { - var delta = wheelEventDelta(e); - delta.x *= wheelPixelsPerUnit; - delta.y *= wheelPixelsPerUnit; - return delta; - }; - - function onScrollWheel(cm, e) { - var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y; - - var display = cm.display, scroll = display.scroller; - // Quit if there's nothing to scroll here - var canScrollX = scroll.scrollWidth > scroll.clientWidth; - var canScrollY = scroll.scrollHeight > scroll.clientHeight; - if (!(dx && canScrollX || dy && canScrollY)) return; - - // Webkit browsers on OS X abort momentum scrolls when the target - // of the scroll event is removed from the scrollable element. - // This hack (see related code in patchDisplay) makes sure the - // element is kept around. - if (dy && mac && webkit) { - outer: for (var cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) { - for (var i = 0; i < view.length; i++) { - if (view[i].node == cur) { - cm.display.currentWheelTarget = cur; - break outer; - } - } - } - } - - // On some browsers, horizontal scrolling will cause redraws to - // happen before the gutter has been realigned, causing it to - // wriggle around in a most unseemly way. When we have an - // estimated pixels/delta value, we just handle horizontal - // scrolling entirely here. It'll be slightly off from native, but - // better than glitching out. - if (dx && !gecko && !presto && wheelPixelsPerUnit != null) { - if (dy && canScrollY) - setScrollTop(cm, Math.max(0, Math.min(scroll.scrollTop + dy * wheelPixelsPerUnit, scroll.scrollHeight - scroll.clientHeight))); - setScrollLeft(cm, Math.max(0, Math.min(scroll.scrollLeft + dx * wheelPixelsPerUnit, scroll.scrollWidth - scroll.clientWidth))); - // Only prevent default scrolling if vertical scrolling is - // actually possible. Otherwise, it causes vertical scroll - // jitter on OSX trackpads when deltaX is small and deltaY - // is large (issue #3579) - if (!dy || (dy && canScrollY)) - e_preventDefault(e); - display.wheelStartX = null; // Abort measurement, if in progress - return; - } - - // 'Project' the visible viewport to cover the area that is being - // scrolled into view (if we know enough to estimate it). - if (dy && wheelPixelsPerUnit != null) { - var pixels = dy * wheelPixelsPerUnit; - var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight; - if (pixels < 0) top = Math.max(0, top + pixels - 50); - else bot = Math.min(cm.doc.height, bot + pixels + 50); - updateDisplaySimple(cm, {top: top, bottom: bot}); - } - - if (wheelSamples < 20) { - if (display.wheelStartX == null) { - display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop; - display.wheelDX = dx; display.wheelDY = dy; - setTimeout(function() { - if (display.wheelStartX == null) return; - var movedX = scroll.scrollLeft - display.wheelStartX; - var movedY = scroll.scrollTop - display.wheelStartY; - var sample = (movedY && display.wheelDY && movedY / display.wheelDY) || - (movedX && display.wheelDX && movedX / display.wheelDX); - display.wheelStartX = display.wheelStartY = null; - if (!sample) return; - wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1); - ++wheelSamples; - }, 200); - } else { - display.wheelDX += dx; display.wheelDY += dy; - } - } - } - - // KEY EVENTS - - // Run a handler that was bound to a key. - function doHandleBinding(cm, bound, dropShift) { - if (typeof bound == "string") { - bound = commands[bound]; - if (!bound) return false; - } - // Ensure previous input has been read, so that the handler sees a - // consistent view of the document - cm.display.input.ensurePolled(); - var prevShift = cm.display.shift, done = false; - try { - if (cm.isReadOnly()) cm.state.suppressEdits = true; - if (dropShift) cm.display.shift = false; - done = bound(cm) != Pass; - } finally { - cm.display.shift = prevShift; - cm.state.suppressEdits = false; - } - return done; - } - - function lookupKeyForEditor(cm, name, handle) { - for (var i = 0; i < cm.state.keyMaps.length; i++) { - var result = lookupKey(name, cm.state.keyMaps[i], handle, cm); - if (result) return result; - } - return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle, cm)) - || lookupKey(name, cm.options.keyMap, handle, cm); - } - - var stopSeq = new Delayed; - function dispatchKey(cm, name, e, handle) { - var seq = cm.state.keySeq; - if (seq) { - if (isModifierKey(name)) return "handled"; - stopSeq.set(50, function() { - if (cm.state.keySeq == seq) { - cm.state.keySeq = null; - cm.display.input.reset(); - } - }); - name = seq + " " + name; - } - var result = lookupKeyForEditor(cm, name, handle); - - if (result == "multi") - cm.state.keySeq = name; - if (result == "handled") - signalLater(cm, "keyHandled", cm, name, e); - - if (result == "handled" || result == "multi") { - e_preventDefault(e); - restartBlink(cm); - } - - if (seq && !result && /\'$/.test(name)) { - e_preventDefault(e); - return true; - } - return !!result; - } - - // Handle a key from the keydown event. - function handleKeyBinding(cm, e) { - var name = keyName(e, true); - if (!name) return false; - - if (e.shiftKey && !cm.state.keySeq) { - // First try to resolve full name (including 'Shift-'). Failing - // that, see if there is a cursor-motion command (starting with - // 'go') bound to the keyname without 'Shift-'. - return dispatchKey(cm, "Shift-" + name, e, function(b) {return doHandleBinding(cm, b, true);}) - || dispatchKey(cm, name, e, function(b) { - if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion) - return doHandleBinding(cm, b); - }); - } else { - return dispatchKey(cm, name, e, function(b) { return doHandleBinding(cm, b); }); - } - } - - // Handle a key from the keypress event - function handleCharBinding(cm, e, ch) { - return dispatchKey(cm, "'" + ch + "'", e, - function(b) { return doHandleBinding(cm, b, true); }); - } - - var lastStoppedKey = null; - function onKeyDown(e) { - var cm = this; - cm.curOp.focus = activeElt(); - if (signalDOMEvent(cm, e)) return; - // IE does strange things with escape. - if (ie && ie_version < 11 && e.keyCode == 27) e.returnValue = false; - var code = e.keyCode; - cm.display.shift = code == 16 || e.shiftKey; - var handled = handleKeyBinding(cm, e); - if (presto) { - lastStoppedKey = handled ? code : null; - // Opera has no cut event... we try to at least catch the key combo - if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey)) - cm.replaceSelection("", null, "cut"); - } - - // Turn mouse into crosshair when Alt is held on Mac. - if (code == 18 && !/\bCodeMirror-crosshair\b/.test(cm.display.lineDiv.className)) - showCrossHair(cm); - } - - function showCrossHair(cm) { - var lineDiv = cm.display.lineDiv; - addClass(lineDiv, "CodeMirror-crosshair"); - - function up(e) { - if (e.keyCode == 18 || !e.altKey) { - rmClass(lineDiv, "CodeMirror-crosshair"); - off(document, "keyup", up); - off(document, "mouseover", up); - } - } - on(document, "keyup", up); - on(document, "mouseover", up); - } - - function onKeyUp(e) { - if (e.keyCode == 16) this.doc.sel.shift = false; - signalDOMEvent(this, e); - } - - function onKeyPress(e) { - var cm = this; - if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) return; - var keyCode = e.keyCode, charCode = e.charCode; - if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;} - if ((presto && (!e.which || e.which < 10)) && handleKeyBinding(cm, e)) return; - var ch = String.fromCharCode(charCode == null ? keyCode : charCode); - if (handleCharBinding(cm, e, ch)) return; - cm.display.input.onKeyPress(e); - } - - // FOCUS/BLUR EVENTS - - function delayBlurEvent(cm) { - cm.state.delayingBlurEvent = true; - setTimeout(function() { - if (cm.state.delayingBlurEvent) { - cm.state.delayingBlurEvent = false; - onBlur(cm); - } - }, 100); - } - - function onFocus(cm) { - if (cm.state.delayingBlurEvent) cm.state.delayingBlurEvent = false; - - if (cm.options.readOnly == "nocursor") return; - if (!cm.state.focused) { - signal(cm, "focus", cm); - cm.state.focused = true; - addClass(cm.display.wrapper, "CodeMirror-focused"); - // This test prevents this from firing when a context - // menu is closed (since the input reset would kill the - // select-all detection hack) - if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) { - cm.display.input.reset(); - if (webkit) setTimeout(function() { cm.display.input.reset(true); }, 20); // Issue #1730 - } - cm.display.input.receivedFocus(); - } - restartBlink(cm); - } - function onBlur(cm) { - if (cm.state.delayingBlurEvent) return; - - if (cm.state.focused) { - signal(cm, "blur", cm); - cm.state.focused = false; - rmClass(cm.display.wrapper, "CodeMirror-focused"); - } - clearInterval(cm.display.blinker); - setTimeout(function() {if (!cm.state.focused) cm.display.shift = false;}, 150); - } - - // CONTEXT MENU HANDLING - - // To make the context menu work, we need to briefly unhide the - // textarea (making it as unobtrusive as possible) to let the - // right-click take effect on it. - function onContextMenu(cm, e) { - if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) return; - if (signalDOMEvent(cm, e, "contextmenu")) return; - cm.display.input.onContextMenu(e); - } - - function contextMenuInGutter(cm, e) { - if (!hasHandler(cm, "gutterContextMenu")) return false; - return gutterEvent(cm, e, "gutterContextMenu", false); - } - - // UPDATING - - // Compute the position of the end of a change (its 'to' property - // refers to the pre-change end). - var changeEnd = CodeMirror.changeEnd = function(change) { - if (!change.text) return change.to; - return Pos(change.from.line + change.text.length - 1, - lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0)); - }; - - // Adjust a position to refer to the post-change position of the - // same text, or the end of the change if the change covers it. - function adjustForChange(pos, change) { - if (cmp(pos, change.from) < 0) return pos; - if (cmp(pos, change.to) <= 0) return changeEnd(change); - - var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch; - if (pos.line == change.to.line) ch += changeEnd(change).ch - change.to.ch; - return Pos(line, ch); - } - - function computeSelAfterChange(doc, change) { - var out = []; - for (var i = 0; i < doc.sel.ranges.length; i++) { - var range = doc.sel.ranges[i]; - out.push(new Range(adjustForChange(range.anchor, change), - adjustForChange(range.head, change))); - } - return normalizeSelection(out, doc.sel.primIndex); - } - - function offsetPos(pos, old, nw) { - if (pos.line == old.line) - return Pos(nw.line, pos.ch - old.ch + nw.ch); - else - return Pos(nw.line + (pos.line - old.line), pos.ch); - } - - // Used by replaceSelections to allow moving the selection to the - // start or around the replaced test. Hint may be "start" or "around". - function computeReplacedSel(doc, changes, hint) { - var out = []; - var oldPrev = Pos(doc.first, 0), newPrev = oldPrev; - for (var i = 0; i < changes.length; i++) { - var change = changes[i]; - var from = offsetPos(change.from, oldPrev, newPrev); - var to = offsetPos(changeEnd(change), oldPrev, newPrev); - oldPrev = change.to; - newPrev = to; - if (hint == "around") { - var range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0; - out[i] = new Range(inv ? to : from, inv ? from : to); - } else { - out[i] = new Range(from, from); - } - } - return new Selection(out, doc.sel.primIndex); - } - - // Allow "beforeChange" event handlers to influence a change - function filterChange(doc, change, update) { - var obj = { - canceled: false, - from: change.from, - to: change.to, - text: change.text, - origin: change.origin, - cancel: function() { this.canceled = true; } - }; - if (update) obj.update = function(from, to, text, origin) { - if (from) this.from = clipPos(doc, from); - if (to) this.to = clipPos(doc, to); - if (text) this.text = text; - if (origin !== undefined) this.origin = origin; - }; - signal(doc, "beforeChange", doc, obj); - if (doc.cm) signal(doc.cm, "beforeChange", doc.cm, obj); - - if (obj.canceled) return null; - return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin}; - } - - // Apply a change to a document, and add it to the document's - // history, and propagating it to all linked documents. - function makeChange(doc, change, ignoreReadOnly) { - if (doc.cm) { - if (!doc.cm.curOp) return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly); - if (doc.cm.state.suppressEdits) return; - } - - if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) { - change = filterChange(doc, change, true); - if (!change) return; - } - - // Possibly split or suppress the update based on the presence - // of read-only spans in its range. - var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to); - if (split) { - for (var i = split.length - 1; i >= 0; --i) - makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [""] : change.text}); - } else { - makeChangeInner(doc, change); - } - } - - function makeChangeInner(doc, change) { - if (change.text.length == 1 && change.text[0] == "" && cmp(change.from, change.to) == 0) return; - var selAfter = computeSelAfterChange(doc, change); - addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN); - - makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change)); - var rebased = []; - - linkedDocs(doc, function(doc, sharedHist) { - if (!sharedHist && indexOf(rebased, doc.history) == -1) { - rebaseHist(doc.history, change); - rebased.push(doc.history); - } - makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change)); - }); - } - - // Revert a change stored in a document's history. - function makeChangeFromHistory(doc, type, allowSelectionOnly) { - if (doc.cm && doc.cm.state.suppressEdits) return; - - var hist = doc.history, event, selAfter = doc.sel; - var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done; - - // Verify that there is a useable event (so that ctrl-z won't - // needlessly clear selection events) - for (var i = 0; i < source.length; i++) { - event = source[i]; - if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges) - break; - } - if (i == source.length) return; - hist.lastOrigin = hist.lastSelOrigin = null; - - for (;;) { - event = source.pop(); - if (event.ranges) { - pushSelectionToHistory(event, dest); - if (allowSelectionOnly && !event.equals(doc.sel)) { - setSelection(doc, event, {clearRedo: false}); - return; - } - selAfter = event; - } - else break; - } - - // Build up a reverse change object to add to the opposite history - // stack (redo when undoing, and vice versa). - var antiChanges = []; - pushSelectionToHistory(selAfter, dest); - dest.push({changes: antiChanges, generation: hist.generation}); - hist.generation = event.generation || ++hist.maxGeneration; - - var filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange"); - - for (var i = event.changes.length - 1; i >= 0; --i) { - var change = event.changes[i]; - change.origin = type; - if (filter && !filterChange(doc, change, false)) { - source.length = 0; - return; - } - - antiChanges.push(historyChangeFromChange(doc, change)); - - var after = i ? computeSelAfterChange(doc, change) : lst(source); - makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change)); - if (!i && doc.cm) doc.cm.scrollIntoView({from: change.from, to: changeEnd(change)}); - var rebased = []; - - // Propagate to the linked documents - linkedDocs(doc, function(doc, sharedHist) { - if (!sharedHist && indexOf(rebased, doc.history) == -1) { - rebaseHist(doc.history, change); - rebased.push(doc.history); - } - makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change)); - }); - } - } - - // Sub-views need their line numbers shifted when text is added - // above or below them in the parent document. - function shiftDoc(doc, distance) { - if (distance == 0) return; - doc.first += distance; - doc.sel = new Selection(map(doc.sel.ranges, function(range) { - return new Range(Pos(range.anchor.line + distance, range.anchor.ch), - Pos(range.head.line + distance, range.head.ch)); - }), doc.sel.primIndex); - if (doc.cm) { - regChange(doc.cm, doc.first, doc.first - distance, distance); - for (var d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++) - regLineChange(doc.cm, l, "gutter"); - } - } - - // More lower-level change function, handling only a single document - // (not linked ones). - function makeChangeSingleDoc(doc, change, selAfter, spans) { - if (doc.cm && !doc.cm.curOp) - return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans); - - if (change.to.line < doc.first) { - shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line)); - return; - } - if (change.from.line > doc.lastLine()) return; - - // Clip the change to the size of this doc - if (change.from.line < doc.first) { - var shift = change.text.length - 1 - (doc.first - change.from.line); - shiftDoc(doc, shift); - change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch), - text: [lst(change.text)], origin: change.origin}; - } - var last = doc.lastLine(); - if (change.to.line > last) { - change = {from: change.from, to: Pos(last, getLine(doc, last).text.length), - text: [change.text[0]], origin: change.origin}; - } - - change.removed = getBetween(doc, change.from, change.to); - - if (!selAfter) selAfter = computeSelAfterChange(doc, change); - if (doc.cm) makeChangeSingleDocInEditor(doc.cm, change, spans); - else updateDoc(doc, change, spans); - setSelectionNoUndo(doc, selAfter, sel_dontScroll); - } - - // Handle the interaction of a change to a document with the editor - // that this document is part of. - function makeChangeSingleDocInEditor(cm, change, spans) { - var doc = cm.doc, display = cm.display, from = change.from, to = change.to; - - var recomputeMaxLength = false, checkWidthStart = from.line; - if (!cm.options.lineWrapping) { - checkWidthStart = lineNo(visualLine(getLine(doc, from.line))); - doc.iter(checkWidthStart, to.line + 1, function(line) { - if (line == display.maxLine) { - recomputeMaxLength = true; - return true; - } - }); - } - - if (doc.sel.contains(change.from, change.to) > -1) - signalCursorActivity(cm); - - updateDoc(doc, change, spans, estimateHeight(cm)); - - if (!cm.options.lineWrapping) { - doc.iter(checkWidthStart, from.line + change.text.length, function(line) { - var len = lineLength(line); - if (len > display.maxLineLength) { - display.maxLine = line; - display.maxLineLength = len; - display.maxLineChanged = true; - recomputeMaxLength = false; - } - }); - if (recomputeMaxLength) cm.curOp.updateMaxLine = true; - } - - // Adjust frontier, schedule worker - doc.frontier = Math.min(doc.frontier, from.line); - startWorker(cm, 400); - - var lendiff = change.text.length - (to.line - from.line) - 1; - // Remember that these lines changed, for updating the display - if (change.full) - regChange(cm); - else if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change)) - regLineChange(cm, from.line, "text"); - else - regChange(cm, from.line, to.line + 1, lendiff); - - var changesHandler = hasHandler(cm, "changes"), changeHandler = hasHandler(cm, "change"); - if (changeHandler || changesHandler) { - var obj = { - from: from, to: to, - text: change.text, - removed: change.removed, - origin: change.origin - }; - if (changeHandler) signalLater(cm, "change", cm, obj); - if (changesHandler) (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj); - } - cm.display.selForContextMenu = null; - } - - function replaceRange(doc, code, from, to, origin) { - if (!to) to = from; - if (cmp(to, from) < 0) { var tmp = to; to = from; from = tmp; } - if (typeof code == "string") code = doc.splitLines(code); - makeChange(doc, {from: from, to: to, text: code, origin: origin}); - } - - // SCROLLING THINGS INTO VIEW - - // If an editor sits on the top or bottom of the window, partially - // scrolled out of view, this ensures that the cursor is visible. - function maybeScrollWindow(cm, coords) { - if (signalDOMEvent(cm, "scrollCursorIntoView")) return; - - var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null; - if (coords.top + box.top < 0) doScroll = true; - else if (coords.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) doScroll = false; - if (doScroll != null && !phantom) { - var scrollNode = elt("div", "\u200b", null, "position: absolute; top: " + - (coords.top - display.viewOffset - paddingTop(cm.display)) + "px; height: " + - (coords.bottom - coords.top + scrollGap(cm) + display.barHeight) + "px; left: " + - coords.left + "px; width: 2px;"); - cm.display.lineSpace.appendChild(scrollNode); - scrollNode.scrollIntoView(doScroll); - cm.display.lineSpace.removeChild(scrollNode); - } - } - - // Scroll a given position into view (immediately), verifying that - // it actually became visible (as line heights are accurately - // measured, the position of something may 'drift' during drawing). - function scrollPosIntoView(cm, pos, end, margin) { - if (margin == null) margin = 0; - for (var limit = 0; limit < 5; limit++) { - var changed = false, coords = cursorCoords(cm, pos); - var endCoords = !end || end == pos ? coords : cursorCoords(cm, end); - var scrollPos = calculateScrollPos(cm, Math.min(coords.left, endCoords.left), - Math.min(coords.top, endCoords.top) - margin, - Math.max(coords.left, endCoords.left), - Math.max(coords.bottom, endCoords.bottom) + margin); - var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft; - if (scrollPos.scrollTop != null) { - setScrollTop(cm, scrollPos.scrollTop); - if (Math.abs(cm.doc.scrollTop - startTop) > 1) changed = true; - } - if (scrollPos.scrollLeft != null) { - setScrollLeft(cm, scrollPos.scrollLeft); - if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) changed = true; - } - if (!changed) break; - } - return coords; - } - - // Scroll a given set of coordinates into view (immediately). - function scrollIntoView(cm, x1, y1, x2, y2) { - var scrollPos = calculateScrollPos(cm, x1, y1, x2, y2); - if (scrollPos.scrollTop != null) setScrollTop(cm, scrollPos.scrollTop); - if (scrollPos.scrollLeft != null) setScrollLeft(cm, scrollPos.scrollLeft); - } - - // Calculate a new scroll position needed to scroll the given - // rectangle into view. Returns an object with scrollTop and - // scrollLeft properties. When these are undefined, the - // vertical/horizontal position does not need to be adjusted. - function calculateScrollPos(cm, x1, y1, x2, y2) { - var display = cm.display, snapMargin = textHeight(cm.display); - if (y1 < 0) y1 = 0; - var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop; - var screen = displayHeight(cm), result = {}; - if (y2 - y1 > screen) y2 = y1 + screen; - var docBottom = cm.doc.height + paddingVert(display); - var atTop = y1 < snapMargin, atBottom = y2 > docBottom - snapMargin; - if (y1 < screentop) { - result.scrollTop = atTop ? 0 : y1; - } else if (y2 > screentop + screen) { - var newTop = Math.min(y1, (atBottom ? docBottom : y2) - screen); - if (newTop != screentop) result.scrollTop = newTop; - } - - var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft; - var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0); - var tooWide = x2 - x1 > screenw; - if (tooWide) x2 = x1 + screenw; - if (x1 < 10) - result.scrollLeft = 0; - else if (x1 < screenleft) - result.scrollLeft = Math.max(0, x1 - (tooWide ? 0 : 10)); - else if (x2 > screenw + screenleft - 3) - result.scrollLeft = x2 + (tooWide ? 0 : 10) - screenw; - return result; - } - - // Store a relative adjustment to the scroll position in the current - // operation (to be applied when the operation finishes). - function addToScrollPos(cm, left, top) { - if (left != null || top != null) resolveScrollToPos(cm); - if (left != null) - cm.curOp.scrollLeft = (cm.curOp.scrollLeft == null ? cm.doc.scrollLeft : cm.curOp.scrollLeft) + left; - if (top != null) - cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top; - } - - // Make sure that at the end of the operation the current cursor is - // shown. - function ensureCursorVisible(cm) { - resolveScrollToPos(cm); - var cur = cm.getCursor(), from = cur, to = cur; - if (!cm.options.lineWrapping) { - from = cur.ch ? Pos(cur.line, cur.ch - 1) : cur; - to = Pos(cur.line, cur.ch + 1); - } - cm.curOp.scrollToPos = {from: from, to: to, margin: cm.options.cursorScrollMargin, isCursor: true}; - } - - // When an operation has its scrollToPos property set, and another - // scroll action is applied before the end of the operation, this - // 'simulates' scrolling that position into view in a cheap way, so - // that the effect of intermediate scroll commands is not ignored. - function resolveScrollToPos(cm) { - var range = cm.curOp.scrollToPos; - if (range) { - cm.curOp.scrollToPos = null; - var from = estimateCoords(cm, range.from), to = estimateCoords(cm, range.to); - var sPos = calculateScrollPos(cm, Math.min(from.left, to.left), - Math.min(from.top, to.top) - range.margin, - Math.max(from.right, to.right), - Math.max(from.bottom, to.bottom) + range.margin); - cm.scrollTo(sPos.scrollLeft, sPos.scrollTop); - } - } - - // API UTILITIES - - // Indent the given line. The how parameter can be "smart", - // "add"/null, "subtract", or "prev". When aggressive is false - // (typically set to true for forced single-line indents), empty - // lines are not indented, and places where the mode returns Pass - // are left alone. - function indentLine(cm, n, how, aggressive) { - var doc = cm.doc, state; - if (how == null) how = "add"; - if (how == "smart") { - // Fall back to "prev" when the mode doesn't have an indentation - // method. - if (!doc.mode.indent) how = "prev"; - else state = getStateBefore(cm, n); - } - - var tabSize = cm.options.tabSize; - var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize); - if (line.stateAfter) line.stateAfter = null; - var curSpaceString = line.text.match(/^\s*/)[0], indentation; - if (!aggressive && !/\S/.test(line.text)) { - indentation = 0; - how = "not"; - } else if (how == "smart") { - indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text); - if (indentation == Pass || indentation > 150) { - if (!aggressive) return; - how = "prev"; - } - } - if (how == "prev") { - if (n > doc.first) indentation = countColumn(getLine(doc, n-1).text, null, tabSize); - else indentation = 0; - } else if (how == "add") { - indentation = curSpace + cm.options.indentUnit; - } else if (how == "subtract") { - indentation = curSpace - cm.options.indentUnit; - } else if (typeof how == "number") { - indentation = curSpace + how; - } - indentation = Math.max(0, indentation); - - var indentString = "", pos = 0; - if (cm.options.indentWithTabs) - for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";} - if (pos < indentation) indentString += spaceStr(indentation - pos); - - if (indentString != curSpaceString) { - replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input"); - line.stateAfter = null; - return true; - } else { - // Ensure that, if the cursor was in the whitespace at the start - // of the line, it is moved to the end of that space. - for (var i = 0; i < doc.sel.ranges.length; i++) { - var range = doc.sel.ranges[i]; - if (range.head.line == n && range.head.ch < curSpaceString.length) { - var pos = Pos(n, curSpaceString.length); - replaceOneSelection(doc, i, new Range(pos, pos)); - break; - } - } - } - } - - // Utility for applying a change to a line by handle or number, - // returning the number and optionally registering the line as - // changed. - function changeLine(doc, handle, changeType, op) { - var no = handle, line = handle; - if (typeof handle == "number") line = getLine(doc, clipLine(doc, handle)); - else no = lineNo(handle); - if (no == null) return null; - if (op(line, no) && doc.cm) regLineChange(doc.cm, no, changeType); - return line; - } - - // Helper for deleting text near the selection(s), used to implement - // backspace, delete, and similar functionality. - function deleteNearSelection(cm, compute) { - var ranges = cm.doc.sel.ranges, kill = []; - // Build up a set of ranges to kill first, merging overlapping - // ranges. - for (var i = 0; i < ranges.length; i++) { - var toKill = compute(ranges[i]); - while (kill.length && cmp(toKill.from, lst(kill).to) <= 0) { - var replaced = kill.pop(); - if (cmp(replaced.from, toKill.from) < 0) { - toKill.from = replaced.from; - break; - } - } - kill.push(toKill); - } - // Next, remove those actual ranges. - runInOp(cm, function() { - for (var i = kill.length - 1; i >= 0; i--) - replaceRange(cm.doc, "", kill[i].from, kill[i].to, "+delete"); - ensureCursorVisible(cm); - }); - } - - // Used for horizontal relative motion. Dir is -1 or 1 (left or - // right), unit can be "char", "column" (like char, but doesn't - // cross line boundaries), "word" (across next word), or "group" (to - // the start of next group of word or non-word-non-whitespace - // chars). The visually param controls whether, in right-to-left - // text, direction 1 means to move towards the next index in the - // string, or towards the character to the right of the current - // position. The resulting position will have a hitSide=true - // property if it reached the end of the document. - function findPosH(doc, pos, dir, unit, visually) { - var line = pos.line, ch = pos.ch, origDir = dir; - var lineObj = getLine(doc, line); - function findNextLine() { - var l = line + dir; - if (l < doc.first || l >= doc.first + doc.size) return false - line = l; - return lineObj = getLine(doc, l); - } - function moveOnce(boundToLine) { - var next = (visually ? moveVisually : moveLogically)(lineObj, ch, dir, true); - if (next == null) { - if (!boundToLine && findNextLine()) { - if (visually) ch = (dir < 0 ? lineRight : lineLeft)(lineObj); - else ch = dir < 0 ? lineObj.text.length : 0; - } else return false - } else ch = next; - return true; - } - - if (unit == "char") { - moveOnce() - } else if (unit == "column") { - moveOnce(true) - } else if (unit == "word" || unit == "group") { - var sawType = null, group = unit == "group"; - var helper = doc.cm && doc.cm.getHelper(pos, "wordChars"); - for (var first = true;; first = false) { - if (dir < 0 && !moveOnce(!first)) break; - var cur = lineObj.text.charAt(ch) || "\n"; - var type = isWordChar(cur, helper) ? "w" - : group && cur == "\n" ? "n" - : !group || /\s/.test(cur) ? null - : "p"; - if (group && !first && !type) type = "s"; - if (sawType && sawType != type) { - if (dir < 0) {dir = 1; moveOnce();} - break; - } - - if (type) sawType = type; - if (dir > 0 && !moveOnce(!first)) break; - } - } - var result = skipAtomic(doc, Pos(line, ch), pos, origDir, true); - if (!cmp(pos, result)) result.hitSide = true; - return result; - } - - // For relative vertical movement. Dir may be -1 or 1. Unit can be - // "page" or "line". The resulting position will have a hitSide=true - // property if it reached the end of the document. - function findPosV(cm, pos, dir, unit) { - var doc = cm.doc, x = pos.left, y; - if (unit == "page") { - var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight); - y = pos.top + dir * (pageSize - (dir < 0 ? 1.5 : .5) * textHeight(cm.display)); - } else if (unit == "line") { - y = dir > 0 ? pos.bottom + 3 : pos.top - 3; - } - for (;;) { - var target = coordsChar(cm, x, y); - if (!target.outside) break; - if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break; } - y += dir * 5; - } - return target; - } - - // EDITOR METHODS - - // The publicly visible API. Note that methodOp(f) means - // 'wrap f in an operation, performed on its `this` parameter'. - - // This is not the complete set of editor methods. Most of the - // methods defined on the Doc type are also injected into - // CodeMirror.prototype, for backwards compatibility and - // convenience. - - CodeMirror.prototype = { - constructor: CodeMirror, - focus: function(){window.focus(); this.display.input.focus();}, - - setOption: function(option, value) { - var options = this.options, old = options[option]; - if (options[option] == value && option != "mode") return; - options[option] = value; - if (optionHandlers.hasOwnProperty(option)) - operation(this, optionHandlers[option])(this, value, old); - }, - - getOption: function(option) {return this.options[option];}, - getDoc: function() {return this.doc;}, - - addKeyMap: function(map, bottom) { - this.state.keyMaps[bottom ? "push" : "unshift"](getKeyMap(map)); - }, - removeKeyMap: function(map) { - var maps = this.state.keyMaps; - for (var i = 0; i < maps.length; ++i) - if (maps[i] == map || maps[i].name == map) { - maps.splice(i, 1); - return true; - } - }, - - addOverlay: methodOp(function(spec, options) { - var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec); - if (mode.startState) throw new Error("Overlays may not be stateful."); - this.state.overlays.push({mode: mode, modeSpec: spec, opaque: options && options.opaque}); - this.state.modeGen++; - regChange(this); - }), - removeOverlay: methodOp(function(spec) { - var overlays = this.state.overlays; - for (var i = 0; i < overlays.length; ++i) { - var cur = overlays[i].modeSpec; - if (cur == spec || typeof spec == "string" && cur.name == spec) { - overlays.splice(i, 1); - this.state.modeGen++; - regChange(this); - return; - } - } - }), - - indentLine: methodOp(function(n, dir, aggressive) { - if (typeof dir != "string" && typeof dir != "number") { - if (dir == null) dir = this.options.smartIndent ? "smart" : "prev"; - else dir = dir ? "add" : "subtract"; - } - if (isLine(this.doc, n)) indentLine(this, n, dir, aggressive); - }), - indentSelection: methodOp(function(how) { - var ranges = this.doc.sel.ranges, end = -1; - for (var i = 0; i < ranges.length; i++) { - var range = ranges[i]; - if (!range.empty()) { - var from = range.from(), to = range.to(); - var start = Math.max(end, from.line); - end = Math.min(this.lastLine(), to.line - (to.ch ? 0 : 1)) + 1; - for (var j = start; j < end; ++j) - indentLine(this, j, how); - var newRanges = this.doc.sel.ranges; - if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0) - replaceOneSelection(this.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll); - } else if (range.head.line > end) { - indentLine(this, range.head.line, how, true); - end = range.head.line; - if (i == this.doc.sel.primIndex) ensureCursorVisible(this); - } - } - }), - - // Fetch the parser token for a given character. Useful for hacks - // that want to inspect the mode state (say, for completion). - getTokenAt: function(pos, precise) { - return takeToken(this, pos, precise); - }, - - getLineTokens: function(line, precise) { - return takeToken(this, Pos(line), precise, true); - }, - - getTokenTypeAt: function(pos) { - pos = clipPos(this.doc, pos); - var styles = getLineStyles(this, getLine(this.doc, pos.line)); - var before = 0, after = (styles.length - 1) / 2, ch = pos.ch; - var type; - if (ch == 0) type = styles[2]; - else for (;;) { - var mid = (before + after) >> 1; - if ((mid ? styles[mid * 2 - 1] : 0) >= ch) after = mid; - else if (styles[mid * 2 + 1] < ch) before = mid + 1; - else { type = styles[mid * 2 + 2]; break; } - } - var cut = type ? type.indexOf("cm-overlay ") : -1; - return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1); - }, - - getModeAt: function(pos) { - var mode = this.doc.mode; - if (!mode.innerMode) return mode; - return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode; - }, - - getHelper: function(pos, type) { - return this.getHelpers(pos, type)[0]; - }, - - getHelpers: function(pos, type) { - var found = []; - if (!helpers.hasOwnProperty(type)) return found; - var help = helpers[type], mode = this.getModeAt(pos); - if (typeof mode[type] == "string") { - if (help[mode[type]]) found.push(help[mode[type]]); - } else if (mode[type]) { - for (var i = 0; i < mode[type].length; i++) { - var val = help[mode[type][i]]; - if (val) found.push(val); - } - } else if (mode.helperType && help[mode.helperType]) { - found.push(help[mode.helperType]); - } else if (help[mode.name]) { - found.push(help[mode.name]); - } - for (var i = 0; i < help._global.length; i++) { - var cur = help._global[i]; - if (cur.pred(mode, this) && indexOf(found, cur.val) == -1) - found.push(cur.val); - } - return found; - }, - - getStateAfter: function(line, precise) { - var doc = this.doc; - line = clipLine(doc, line == null ? doc.first + doc.size - 1: line); - return getStateBefore(this, line + 1, precise); - }, - - cursorCoords: function(start, mode) { - var pos, range = this.doc.sel.primary(); - if (start == null) pos = range.head; - else if (typeof start == "object") pos = clipPos(this.doc, start); - else pos = start ? range.from() : range.to(); - return cursorCoords(this, pos, mode || "page"); - }, - - charCoords: function(pos, mode) { - return charCoords(this, clipPos(this.doc, pos), mode || "page"); - }, - - coordsChar: function(coords, mode) { - coords = fromCoordSystem(this, coords, mode || "page"); - return coordsChar(this, coords.left, coords.top); - }, - - lineAtHeight: function(height, mode) { - height = fromCoordSystem(this, {top: height, left: 0}, mode || "page").top; - return lineAtHeight(this.doc, height + this.display.viewOffset); - }, - heightAtLine: function(line, mode) { - var end = false, lineObj; - if (typeof line == "number") { - var last = this.doc.first + this.doc.size - 1; - if (line < this.doc.first) line = this.doc.first; - else if (line > last) { line = last; end = true; } - lineObj = getLine(this.doc, line); - } else { - lineObj = line; - } - return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || "page").top + - (end ? this.doc.height - heightAtLine(lineObj) : 0); - }, - - defaultTextHeight: function() { return textHeight(this.display); }, - defaultCharWidth: function() { return charWidth(this.display); }, - - setGutterMarker: methodOp(function(line, gutterID, value) { - return changeLine(this.doc, line, "gutter", function(line) { - var markers = line.gutterMarkers || (line.gutterMarkers = {}); - markers[gutterID] = value; - if (!value && isEmpty(markers)) line.gutterMarkers = null; - return true; - }); - }), - - clearGutter: methodOp(function(gutterID) { - var cm = this, doc = cm.doc, i = doc.first; - doc.iter(function(line) { - if (line.gutterMarkers && line.gutterMarkers[gutterID]) { - line.gutterMarkers[gutterID] = null; - regLineChange(cm, i, "gutter"); - if (isEmpty(line.gutterMarkers)) line.gutterMarkers = null; - } - ++i; - }); - }), - - lineInfo: function(line) { - if (typeof line == "number") { - if (!isLine(this.doc, line)) return null; - var n = line; - line = getLine(this.doc, line); - if (!line) return null; - } else { - var n = lineNo(line); - if (n == null) return null; - } - return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers, - textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass, - widgets: line.widgets}; - }, - - getViewport: function() { return {from: this.display.viewFrom, to: this.display.viewTo};}, - - addWidget: function(pos, node, scroll, vert, horiz) { - var display = this.display; - pos = cursorCoords(this, clipPos(this.doc, pos)); - var top = pos.bottom, left = pos.left; - node.style.position = "absolute"; - node.setAttribute("cm-ignore-events", "true"); - this.display.input.setUneditable(node); - display.sizer.appendChild(node); - if (vert == "over") { - top = pos.top; - } else if (vert == "above" || vert == "near") { - var vspace = Math.max(display.wrapper.clientHeight, this.doc.height), - hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth); - // Default to positioning above (if specified and possible); otherwise default to positioning below - if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight) - top = pos.top - node.offsetHeight; - else if (pos.bottom + node.offsetHeight <= vspace) - top = pos.bottom; - if (left + node.offsetWidth > hspace) - left = hspace - node.offsetWidth; - } - node.style.top = top + "px"; - node.style.left = node.style.right = ""; - if (horiz == "right") { - left = display.sizer.clientWidth - node.offsetWidth; - node.style.right = "0px"; - } else { - if (horiz == "left") left = 0; - else if (horiz == "middle") left = (display.sizer.clientWidth - node.offsetWidth) / 2; - node.style.left = left + "px"; - } - if (scroll) - scrollIntoView(this, left, top, left + node.offsetWidth, top + node.offsetHeight); - }, - - triggerOnKeyDown: methodOp(onKeyDown), - triggerOnKeyPress: methodOp(onKeyPress), - triggerOnKeyUp: onKeyUp, - - execCommand: function(cmd) { - if (commands.hasOwnProperty(cmd)) - return commands[cmd].call(null, this); - }, - - triggerElectric: methodOp(function(text) { triggerElectric(this, text); }), - - findPosH: function(from, amount, unit, visually) { - var dir = 1; - if (amount < 0) { dir = -1; amount = -amount; } - for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) { - cur = findPosH(this.doc, cur, dir, unit, visually); - if (cur.hitSide) break; - } - return cur; - }, - - moveH: methodOp(function(dir, unit) { - var cm = this; - cm.extendSelectionsBy(function(range) { - if (cm.display.shift || cm.doc.extend || range.empty()) - return findPosH(cm.doc, range.head, dir, unit, cm.options.rtlMoveVisually); - else - return dir < 0 ? range.from() : range.to(); - }, sel_move); - }), - - deleteH: methodOp(function(dir, unit) { - var sel = this.doc.sel, doc = this.doc; - if (sel.somethingSelected()) - doc.replaceSelection("", null, "+delete"); - else - deleteNearSelection(this, function(range) { - var other = findPosH(doc, range.head, dir, unit, false); - return dir < 0 ? {from: other, to: range.head} : {from: range.head, to: other}; - }); - }), - - findPosV: function(from, amount, unit, goalColumn) { - var dir = 1, x = goalColumn; - if (amount < 0) { dir = -1; amount = -amount; } - for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) { - var coords = cursorCoords(this, cur, "div"); - if (x == null) x = coords.left; - else coords.left = x; - cur = findPosV(this, coords, dir, unit); - if (cur.hitSide) break; - } - return cur; - }, - - moveV: methodOp(function(dir, unit) { - var cm = this, doc = this.doc, goals = []; - var collapse = !cm.display.shift && !doc.extend && doc.sel.somethingSelected(); - doc.extendSelectionsBy(function(range) { - if (collapse) - return dir < 0 ? range.from() : range.to(); - var headPos = cursorCoords(cm, range.head, "div"); - if (range.goalColumn != null) headPos.left = range.goalColumn; - goals.push(headPos.left); - var pos = findPosV(cm, headPos, dir, unit); - if (unit == "page" && range == doc.sel.primary()) - addToScrollPos(cm, null, charCoords(cm, pos, "div").top - headPos.top); - return pos; - }, sel_move); - if (goals.length) for (var i = 0; i < doc.sel.ranges.length; i++) - doc.sel.ranges[i].goalColumn = goals[i]; - }), - - // Find the word at the given position (as returned by coordsChar). - findWordAt: function(pos) { - var doc = this.doc, line = getLine(doc, pos.line).text; - var start = pos.ch, end = pos.ch; - if (line) { - var helper = this.getHelper(pos, "wordChars"); - if ((pos.xRel < 0 || end == line.length) && start) --start; else ++end; - var startChar = line.charAt(start); - var check = isWordChar(startChar, helper) - ? function(ch) { return isWordChar(ch, helper); } - : /\s/.test(startChar) ? function(ch) {return /\s/.test(ch);} - : function(ch) {return !/\s/.test(ch) && !isWordChar(ch);}; - while (start > 0 && check(line.charAt(start - 1))) --start; - while (end < line.length && check(line.charAt(end))) ++end; - } - return new Range(Pos(pos.line, start), Pos(pos.line, end)); - }, - - toggleOverwrite: function(value) { - if (value != null && value == this.state.overwrite) return; - if (this.state.overwrite = !this.state.overwrite) - addClass(this.display.cursorDiv, "CodeMirror-overwrite"); - else - rmClass(this.display.cursorDiv, "CodeMirror-overwrite"); - - signal(this, "overwriteToggle", this, this.state.overwrite); - }, - hasFocus: function() { return this.display.input.getField() == activeElt(); }, - isReadOnly: function() { return !!(this.options.readOnly || this.doc.cantEdit); }, - - scrollTo: methodOp(function(x, y) { - if (x != null || y != null) resolveScrollToPos(this); - if (x != null) this.curOp.scrollLeft = x; - if (y != null) this.curOp.scrollTop = y; - }), - getScrollInfo: function() { - var scroller = this.display.scroller; - return {left: scroller.scrollLeft, top: scroller.scrollTop, - height: scroller.scrollHeight - scrollGap(this) - this.display.barHeight, - width: scroller.scrollWidth - scrollGap(this) - this.display.barWidth, - clientHeight: displayHeight(this), clientWidth: displayWidth(this)}; - }, - - scrollIntoView: methodOp(function(range, margin) { - if (range == null) { - range = {from: this.doc.sel.primary().head, to: null}; - if (margin == null) margin = this.options.cursorScrollMargin; - } else if (typeof range == "number") { - range = {from: Pos(range, 0), to: null}; - } else if (range.from == null) { - range = {from: range, to: null}; - } - if (!range.to) range.to = range.from; - range.margin = margin || 0; - - if (range.from.line != null) { - resolveScrollToPos(this); - this.curOp.scrollToPos = range; - } else { - var sPos = calculateScrollPos(this, Math.min(range.from.left, range.to.left), - Math.min(range.from.top, range.to.top) - range.margin, - Math.max(range.from.right, range.to.right), - Math.max(range.from.bottom, range.to.bottom) + range.margin); - this.scrollTo(sPos.scrollLeft, sPos.scrollTop); - } - }), - - setSize: methodOp(function(width, height) { - var cm = this; - function interpret(val) { - return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val; - } - if (width != null) cm.display.wrapper.style.width = interpret(width); - if (height != null) cm.display.wrapper.style.height = interpret(height); - if (cm.options.lineWrapping) clearLineMeasurementCache(this); - var lineNo = cm.display.viewFrom; - cm.doc.iter(lineNo, cm.display.viewTo, function(line) { - if (line.widgets) for (var i = 0; i < line.widgets.length; i++) - if (line.widgets[i].noHScroll) { regLineChange(cm, lineNo, "widget"); break; } - ++lineNo; - }); - cm.curOp.forceUpdate = true; - signal(cm, "refresh", this); - }), - - operation: function(f){return runInOp(this, f);}, - - refresh: methodOp(function() { - var oldHeight = this.display.cachedTextHeight; - regChange(this); - this.curOp.forceUpdate = true; - clearCaches(this); - this.scrollTo(this.doc.scrollLeft, this.doc.scrollTop); - updateGutterSpace(this); - if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5) - estimateLineHeights(this); - signal(this, "refresh", this); - }), - - swapDoc: methodOp(function(doc) { - var old = this.doc; - old.cm = null; - attachDoc(this, doc); - clearCaches(this); - this.display.input.reset(); - this.scrollTo(doc.scrollLeft, doc.scrollTop); - this.curOp.forceScroll = true; - signalLater(this, "swapDoc", this, old); - return old; - }), - - getInputField: function(){return this.display.input.getField();}, - getWrapperElement: function(){return this.display.wrapper;}, - getScrollerElement: function(){return this.display.scroller;}, - getGutterElement: function(){return this.display.gutters;} - }; - eventMixin(CodeMirror); - - // OPTION DEFAULTS - - // The default configuration options. - var defaults = CodeMirror.defaults = {}; - // Functions to run when options are changed. - var optionHandlers = CodeMirror.optionHandlers = {}; - - function option(name, deflt, handle, notOnInit) { - CodeMirror.defaults[name] = deflt; - if (handle) optionHandlers[name] = - notOnInit ? function(cm, val, old) {if (old != Init) handle(cm, val, old);} : handle; - } - - // Passed to option handlers when there is no old value. - var Init = CodeMirror.Init = {toString: function(){return "CodeMirror.Init";}}; - - // These two are, on init, called from the constructor because they - // have to be initialized before the editor can start at all. - option("value", "", function(cm, val) { - cm.setValue(val); - }, true); - option("mode", null, function(cm, val) { - cm.doc.modeOption = val; - loadMode(cm); - }, true); - - option("indentUnit", 2, loadMode, true); - option("indentWithTabs", false); - option("smartIndent", true); - option("tabSize", 4, function(cm) { - resetModeState(cm); - clearCaches(cm); - regChange(cm); - }, true); - option("lineSeparator", null, function(cm, val) { - cm.doc.lineSep = val; - if (!val) return; - var newBreaks = [], lineNo = cm.doc.first; - cm.doc.iter(function(line) { - for (var pos = 0;;) { - var found = line.text.indexOf(val, pos); - if (found == -1) break; - pos = found + val.length; - newBreaks.push(Pos(lineNo, found)); - } - lineNo++; - }); - for (var i = newBreaks.length - 1; i >= 0; i--) - replaceRange(cm.doc, val, newBreaks[i], Pos(newBreaks[i].line, newBreaks[i].ch + val.length)) - }); - option("specialChars", /[\t\u0000-\u0019\u00ad\u200b-\u200f\u2028\u2029\ufeff]/g, function(cm, val, old) { - cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g"); - if (old != CodeMirror.Init) cm.refresh(); - }); - option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function(cm) {cm.refresh();}, true); - option("electricChars", true); - option("inputStyle", mobile ? "contenteditable" : "textarea", function() { - throw new Error("inputStyle can not (yet) be changed in a running editor"); // FIXME - }, true); - option("rtlMoveVisually", !windows); - option("wholeLineUpdateBefore", true); - - option("theme", "default", function(cm) { - themeChanged(cm); - guttersChanged(cm); - }, true); - option("keyMap", "default", function(cm, val, old) { - var next = getKeyMap(val); - var prev = old != CodeMirror.Init && getKeyMap(old); - if (prev && prev.detach) prev.detach(cm, next); - if (next.attach) next.attach(cm, prev || null); - }); - option("extraKeys", null); - - option("lineWrapping", false, wrappingChanged, true); - option("gutters", [], function(cm) { - setGuttersForLineNumbers(cm.options); - guttersChanged(cm); - }, true); - option("fixedGutter", true, function(cm, val) { - cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0"; - cm.refresh(); - }, true); - option("coverGutterNextToScrollbar", false, function(cm) {updateScrollbars(cm);}, true); - option("scrollbarStyle", "native", function(cm) { - initScrollbars(cm); - updateScrollbars(cm); - cm.display.scrollbars.setScrollTop(cm.doc.scrollTop); - cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft); - }, true); - option("lineNumbers", false, function(cm) { - setGuttersForLineNumbers(cm.options); - guttersChanged(cm); - }, true); - option("firstLineNumber", 1, guttersChanged, true); - option("lineNumberFormatter", function(integer) {return integer;}, guttersChanged, true); - option("showCursorWhenSelecting", false, updateSelection, true); - - option("resetSelectionOnContextMenu", true); - option("lineWiseCopyCut", true); - - option("readOnly", false, function(cm, val) { - if (val == "nocursor") { - onBlur(cm); - cm.display.input.blur(); - cm.display.disabled = true; - } else { - cm.display.disabled = false; - } - cm.display.input.readOnlyChanged(val) - }); - option("disableInput", false, function(cm, val) {if (!val) cm.display.input.reset();}, true); - option("dragDrop", true, dragDropChanged); - option("allowDropFileTypes", null); - - option("cursorBlinkRate", 530); - option("cursorScrollMargin", 0); - option("cursorHeight", 1, updateSelection, true); - option("singleCursorHeightPerLine", true, updateSelection, true); - option("workTime", 100); - option("workDelay", 100); - option("flattenSpans", true, resetModeState, true); - option("addModeClass", false, resetModeState, true); - option("pollInterval", 100); - option("undoDepth", 200, function(cm, val){cm.doc.history.undoDepth = val;}); - option("historyEventDelay", 1250); - option("viewportMargin", 10, function(cm){cm.refresh();}, true); - option("maxHighlightLength", 10000, resetModeState, true); - option("moveInputWithCursor", true, function(cm, val) { - if (!val) cm.display.input.resetPosition(); - }); - - option("tabindex", null, function(cm, val) { - cm.display.input.getField().tabIndex = val || ""; - }); - option("autofocus", null); - - // MODE DEFINITION AND QUERYING - - // Known modes, by name and by MIME - var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {}; - - // Extra arguments are stored as the mode's dependencies, which is - // used by (legacy) mechanisms like loadmode.js to automatically - // load a mode. (Preferred mechanism is the require/define calls.) - CodeMirror.defineMode = function(name, mode) { - if (!CodeMirror.defaults.mode && name != "null") CodeMirror.defaults.mode = name; - if (arguments.length > 2) - mode.dependencies = Array.prototype.slice.call(arguments, 2); - modes[name] = mode; - }; - - CodeMirror.defineMIME = function(mime, spec) { - mimeModes[mime] = spec; - }; - - // Given a MIME type, a {name, ...options} config object, or a name - // string, return a mode config object. - CodeMirror.resolveMode = function(spec) { - if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) { - spec = mimeModes[spec]; - } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) { - var found = mimeModes[spec.name]; - if (typeof found == "string") found = {name: found}; - spec = createObj(found, spec); - spec.name = found.name; - } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) { - return CodeMirror.resolveMode("application/xml"); - } - if (typeof spec == "string") return {name: spec}; - else return spec || {name: "null"}; - }; - - // Given a mode spec (anything that resolveMode accepts), find and - // initialize an actual mode object. - CodeMirror.getMode = function(options, spec) { - var spec = CodeMirror.resolveMode(spec); - var mfactory = modes[spec.name]; - if (!mfactory) return CodeMirror.getMode(options, "text/plain"); - var modeObj = mfactory(options, spec); - if (modeExtensions.hasOwnProperty(spec.name)) { - var exts = modeExtensions[spec.name]; - for (var prop in exts) { - if (!exts.hasOwnProperty(prop)) continue; - if (modeObj.hasOwnProperty(prop)) modeObj["_" + prop] = modeObj[prop]; - modeObj[prop] = exts[prop]; - } - } - modeObj.name = spec.name; - if (spec.helperType) modeObj.helperType = spec.helperType; - if (spec.modeProps) for (var prop in spec.modeProps) - modeObj[prop] = spec.modeProps[prop]; - - return modeObj; - }; - - // Minimal default mode. - CodeMirror.defineMode("null", function() { - return {token: function(stream) {stream.skipToEnd();}}; - }); - CodeMirror.defineMIME("text/plain", "null"); - - // This can be used to attach properties to mode objects from - // outside the actual mode definition. - var modeExtensions = CodeMirror.modeExtensions = {}; - CodeMirror.extendMode = function(mode, properties) { - var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {}); - copyObj(properties, exts); - }; - - // EXTENSIONS - - CodeMirror.defineExtension = function(name, func) { - CodeMirror.prototype[name] = func; - }; - CodeMirror.defineDocExtension = function(name, func) { - Doc.prototype[name] = func; - }; - CodeMirror.defineOption = option; - - var initHooks = []; - CodeMirror.defineInitHook = function(f) {initHooks.push(f);}; - - var helpers = CodeMirror.helpers = {}; - CodeMirror.registerHelper = function(type, name, value) { - if (!helpers.hasOwnProperty(type)) helpers[type] = CodeMirror[type] = {_global: []}; - helpers[type][name] = value; - }; - CodeMirror.registerGlobalHelper = function(type, name, predicate, value) { - CodeMirror.registerHelper(type, name, value); - helpers[type]._global.push({pred: predicate, val: value}); - }; - - // MODE STATE HANDLING - - // Utility functions for working with state. Exported because nested - // modes need to do this for their inner modes. - - var copyState = CodeMirror.copyState = function(mode, state) { - if (state === true) return state; - if (mode.copyState) return mode.copyState(state); - var nstate = {}; - for (var n in state) { - var val = state[n]; - if (val instanceof Array) val = val.concat([]); - nstate[n] = val; - } - return nstate; - }; - - var startState = CodeMirror.startState = function(mode, a1, a2) { - return mode.startState ? mode.startState(a1, a2) : true; - }; - - // Given a mode and a state (for that mode), find the inner mode and - // state at the position that the state refers to. - CodeMirror.innerMode = function(mode, state) { - while (mode.innerMode) { - var info = mode.innerMode(state); - if (!info || info.mode == mode) break; - state = info.state; - mode = info.mode; - } - return info || {mode: mode, state: state}; - }; - - // STANDARD COMMANDS - - // Commands are parameter-less actions that can be performed on an - // editor, mostly used for keybindings. - var commands = CodeMirror.commands = { - selectAll: function(cm) {cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll);}, - singleSelection: function(cm) { - cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll); - }, - killLine: function(cm) { - deleteNearSelection(cm, function(range) { - if (range.empty()) { - var len = getLine(cm.doc, range.head.line).text.length; - if (range.head.ch == len && range.head.line < cm.lastLine()) - return {from: range.head, to: Pos(range.head.line + 1, 0)}; - else - return {from: range.head, to: Pos(range.head.line, len)}; - } else { - return {from: range.from(), to: range.to()}; - } - }); - }, - deleteLine: function(cm) { - deleteNearSelection(cm, function(range) { - return {from: Pos(range.from().line, 0), - to: clipPos(cm.doc, Pos(range.to().line + 1, 0))}; - }); - }, - delLineLeft: function(cm) { - deleteNearSelection(cm, function(range) { - return {from: Pos(range.from().line, 0), to: range.from()}; - }); - }, - delWrappedLineLeft: function(cm) { - deleteNearSelection(cm, function(range) { - var top = cm.charCoords(range.head, "div").top + 5; - var leftPos = cm.coordsChar({left: 0, top: top}, "div"); - return {from: leftPos, to: range.from()}; - }); - }, - delWrappedLineRight: function(cm) { - deleteNearSelection(cm, function(range) { - var top = cm.charCoords(range.head, "div").top + 5; - var rightPos = cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div"); - return {from: range.from(), to: rightPos }; - }); - }, - undo: function(cm) {cm.undo();}, - redo: function(cm) {cm.redo();}, - undoSelection: function(cm) {cm.undoSelection();}, - redoSelection: function(cm) {cm.redoSelection();}, - goDocStart: function(cm) {cm.extendSelection(Pos(cm.firstLine(), 0));}, - goDocEnd: function(cm) {cm.extendSelection(Pos(cm.lastLine()));}, - goLineStart: function(cm) { - cm.extendSelectionsBy(function(range) { return lineStart(cm, range.head.line); }, - {origin: "+move", bias: 1}); - }, - goLineStartSmart: function(cm) { - cm.extendSelectionsBy(function(range) { - return lineStartSmart(cm, range.head); - }, {origin: "+move", bias: 1}); - }, - goLineEnd: function(cm) { - cm.extendSelectionsBy(function(range) { return lineEnd(cm, range.head.line); }, - {origin: "+move", bias: -1}); - }, - goLineRight: function(cm) { - cm.extendSelectionsBy(function(range) { - var top = cm.charCoords(range.head, "div").top + 5; - return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div"); - }, sel_move); - }, - goLineLeft: function(cm) { - cm.extendSelectionsBy(function(range) { - var top = cm.charCoords(range.head, "div").top + 5; - return cm.coordsChar({left: 0, top: top}, "div"); - }, sel_move); - }, - goLineLeftSmart: function(cm) { - cm.extendSelectionsBy(function(range) { - var top = cm.charCoords(range.head, "div").top + 5; - var pos = cm.coordsChar({left: 0, top: top}, "div"); - if (pos.ch < cm.getLine(pos.line).search(/\S/)) return lineStartSmart(cm, range.head); - return pos; - }, sel_move); - }, - goLineUp: function(cm) {cm.moveV(-1, "line");}, - goLineDown: function(cm) {cm.moveV(1, "line");}, - goPageUp: function(cm) {cm.moveV(-1, "page");}, - goPageDown: function(cm) {cm.moveV(1, "page");}, - goCharLeft: function(cm) {cm.moveH(-1, "char");}, - goCharRight: function(cm) {cm.moveH(1, "char");}, - goColumnLeft: function(cm) {cm.moveH(-1, "column");}, - goColumnRight: function(cm) {cm.moveH(1, "column");}, - goWordLeft: function(cm) {cm.moveH(-1, "word");}, - goGroupRight: function(cm) {cm.moveH(1, "group");}, - goGroupLeft: function(cm) {cm.moveH(-1, "group");}, - goWordRight: function(cm) {cm.moveH(1, "word");}, - delCharBefore: function(cm) {cm.deleteH(-1, "char");}, - delCharAfter: function(cm) {cm.deleteH(1, "char");}, - delWordBefore: function(cm) {cm.deleteH(-1, "word");}, - delWordAfter: function(cm) {cm.deleteH(1, "word");}, - delGroupBefore: function(cm) {cm.deleteH(-1, "group");}, - delGroupAfter: function(cm) {cm.deleteH(1, "group");}, - indentAuto: function(cm) {cm.indentSelection("smart");}, - indentMore: function(cm) {cm.indentSelection("add");}, - indentLess: function(cm) {cm.indentSelection("subtract");}, - insertTab: function(cm) {cm.replaceSelection("\t");}, - insertSoftTab: function(cm) { - var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize; - for (var i = 0; i < ranges.length; i++) { - var pos = ranges[i].from(); - var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize); - spaces.push(new Array(tabSize - col % tabSize + 1).join(" ")); - } - cm.replaceSelections(spaces); - }, - defaultTab: function(cm) { - if (cm.somethingSelected()) cm.indentSelection("add"); - else cm.execCommand("insertTab"); - }, - transposeChars: function(cm) { - runInOp(cm, function() { - var ranges = cm.listSelections(), newSel = []; - for (var i = 0; i < ranges.length; i++) { - var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text; - if (line) { - if (cur.ch == line.length) cur = new Pos(cur.line, cur.ch - 1); - if (cur.ch > 0) { - cur = new Pos(cur.line, cur.ch + 1); - cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2), - Pos(cur.line, cur.ch - 2), cur, "+transpose"); - } else if (cur.line > cm.doc.first) { - var prev = getLine(cm.doc, cur.line - 1).text; - if (prev) - cm.replaceRange(line.charAt(0) + cm.doc.lineSeparator() + - prev.charAt(prev.length - 1), - Pos(cur.line - 1, prev.length - 1), Pos(cur.line, 1), "+transpose"); - } - } - newSel.push(new Range(cur, cur)); - } - cm.setSelections(newSel); - }); - }, - newlineAndIndent: function(cm) { - runInOp(cm, function() { - var len = cm.listSelections().length; - for (var i = 0; i < len; i++) { - var range = cm.listSelections()[i]; - cm.replaceRange(cm.doc.lineSeparator(), range.anchor, range.head, "+input"); - cm.indentLine(range.from().line + 1, null, true); - } - ensureCursorVisible(cm); - }); - }, - toggleOverwrite: function(cm) {cm.toggleOverwrite();} - }; - - - // STANDARD KEYMAPS - - var keyMap = CodeMirror.keyMap = {}; - - keyMap.basic = { - "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown", - "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown", - "Delete": "delCharAfter", "Backspace": "delCharBefore", "Shift-Backspace": "delCharBefore", - "Tab": "defaultTab", "Shift-Tab": "indentAuto", - "Enter": "newlineAndIndent", "Insert": "toggleOverwrite", - "Esc": "singleSelection" - }; - // Note that the save and find-related commands aren't defined by - // default. User code or addons can define them. Unknown commands - // are simply ignored. - keyMap.pcDefault = { - "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo", - "Ctrl-Home": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Up": "goLineUp", "Ctrl-Down": "goLineDown", - "Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd", - "Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find", - "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll", - "Ctrl-[": "indentLess", "Ctrl-]": "indentMore", - "Ctrl-U": "undoSelection", "Shift-Ctrl-U": "redoSelection", "Alt-U": "redoSelection", - fallthrough: "basic" - }; - // Very basic readline/emacs-style bindings, which are standard on Mac. - keyMap.emacsy = { - "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown", - "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd", - "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore", - "Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars" - }; - keyMap.macDefault = { - "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo", - "Cmd-Home": "goDocStart", "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft", - "Alt-Right": "goGroupRight", "Cmd-Left": "goLineLeft", "Cmd-Right": "goLineRight", "Alt-Backspace": "delGroupBefore", - "Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find", - "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll", - "Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delWrappedLineLeft", "Cmd-Delete": "delWrappedLineRight", - "Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection", "Ctrl-Up": "goDocStart", "Ctrl-Down": "goDocEnd", - fallthrough: ["basic", "emacsy"] - }; - keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault; - - // KEYMAP DISPATCH - - function normalizeKeyName(name) { - var parts = name.split(/-(?!$)/), name = parts[parts.length - 1]; - var alt, ctrl, shift, cmd; - for (var i = 0; i < parts.length - 1; i++) { - var mod = parts[i]; - if (/^(cmd|meta|m)$/i.test(mod)) cmd = true; - else if (/^a(lt)?$/i.test(mod)) alt = true; - else if (/^(c|ctrl|control)$/i.test(mod)) ctrl = true; - else if (/^s(hift)$/i.test(mod)) shift = true; - else throw new Error("Unrecognized modifier name: " + mod); - } - if (alt) name = "Alt-" + name; - if (ctrl) name = "Ctrl-" + name; - if (cmd) name = "Cmd-" + name; - if (shift) name = "Shift-" + name; - return name; - } - - // This is a kludge to keep keymaps mostly working as raw objects - // (backwards compatibility) while at the same time support features - // like normalization and multi-stroke key bindings. It compiles a - // new normalized keymap, and then updates the old object to reflect - // this. - CodeMirror.normalizeKeyMap = function(keymap) { - var copy = {}; - for (var keyname in keymap) if (keymap.hasOwnProperty(keyname)) { - var value = keymap[keyname]; - if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) continue; - if (value == "...") { delete keymap[keyname]; continue; } - - var keys = map(keyname.split(" "), normalizeKeyName); - for (var i = 0; i < keys.length; i++) { - var val, name; - if (i == keys.length - 1) { - name = keys.join(" "); - val = value; - } else { - name = keys.slice(0, i + 1).join(" "); - val = "..."; - } - var prev = copy[name]; - if (!prev) copy[name] = val; - else if (prev != val) throw new Error("Inconsistent bindings for " + name); - } - delete keymap[keyname]; - } - for (var prop in copy) keymap[prop] = copy[prop]; - return keymap; - }; - - var lookupKey = CodeMirror.lookupKey = function(key, map, handle, context) { - map = getKeyMap(map); - var found = map.call ? map.call(key, context) : map[key]; - if (found === false) return "nothing"; - if (found === "...") return "multi"; - if (found != null && handle(found)) return "handled"; - - if (map.fallthrough) { - if (Object.prototype.toString.call(map.fallthrough) != "[object Array]") - return lookupKey(key, map.fallthrough, handle, context); - for (var i = 0; i < map.fallthrough.length; i++) { - var result = lookupKey(key, map.fallthrough[i], handle, context); - if (result) return result; - } - } - }; - - // Modifier key presses don't count as 'real' key presses for the - // purpose of keymap fallthrough. - var isModifierKey = CodeMirror.isModifierKey = function(value) { - var name = typeof value == "string" ? value : keyNames[value.keyCode]; - return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod"; - }; - - // Look up the name of a key as indicated by an event object. - var keyName = CodeMirror.keyName = function(event, noShift) { - if (presto && event.keyCode == 34 && event["char"]) return false; - var base = keyNames[event.keyCode], name = base; - if (name == null || event.altGraphKey) return false; - if (event.altKey && base != "Alt") name = "Alt-" + name; - if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != "Ctrl") name = "Ctrl-" + name; - if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Cmd") name = "Cmd-" + name; - if (!noShift && event.shiftKey && base != "Shift") name = "Shift-" + name; - return name; - }; - - function getKeyMap(val) { - return typeof val == "string" ? keyMap[val] : val; - } - - // FROMTEXTAREA - - CodeMirror.fromTextArea = function(textarea, options) { - options = options ? copyObj(options) : {}; - options.value = textarea.value; - if (!options.tabindex && textarea.tabIndex) - options.tabindex = textarea.tabIndex; - if (!options.placeholder && textarea.placeholder) - options.placeholder = textarea.placeholder; - // Set autofocus to true if this textarea is focused, or if it has - // autofocus and no other element is focused. - if (options.autofocus == null) { - var hasFocus = activeElt(); - options.autofocus = hasFocus == textarea || - textarea.getAttribute("autofocus") != null && hasFocus == document.body; - } - - function save() {textarea.value = cm.getValue();} - if (textarea.form) { - on(textarea.form, "submit", save); - // Deplorable hack to make the submit method do the right thing. - if (!options.leaveSubmitMethodAlone) { - var form = textarea.form, realSubmit = form.submit; - try { - var wrappedSubmit = form.submit = function() { - save(); - form.submit = realSubmit; - form.submit(); - form.submit = wrappedSubmit; - }; - } catch(e) {} - } - } - - options.finishInit = function(cm) { - cm.save = save; - cm.getTextArea = function() { return textarea; }; - cm.toTextArea = function() { - cm.toTextArea = isNaN; // Prevent this from being ran twice - save(); - textarea.parentNode.removeChild(cm.getWrapperElement()); - textarea.style.display = ""; - if (textarea.form) { - off(textarea.form, "submit", save); - if (typeof textarea.form.submit == "function") - textarea.form.submit = realSubmit; - } - }; - }; - - textarea.style.display = "none"; - var cm = CodeMirror(function(node) { - textarea.parentNode.insertBefore(node, textarea.nextSibling); - }, options); - return cm; - }; - - // STRING STREAM - - // Fed to the mode parsers, provides helper functions to make - // parsers more succinct. - - var StringStream = CodeMirror.StringStream = function(string, tabSize) { - this.pos = this.start = 0; - this.string = string; - this.tabSize = tabSize || 8; - this.lastColumnPos = this.lastColumnValue = 0; - this.lineStart = 0; - }; - - StringStream.prototype = { - eol: function() {return this.pos >= this.string.length;}, - sol: function() {return this.pos == this.lineStart;}, - peek: function() {return this.string.charAt(this.pos) || undefined;}, - next: function() { - if (this.pos < this.string.length) - return this.string.charAt(this.pos++); - }, - eat: function(match) { - var ch = this.string.charAt(this.pos); - if (typeof match == "string") var ok = ch == match; - else var ok = ch && (match.test ? match.test(ch) : match(ch)); - if (ok) {++this.pos; return ch;} - }, - eatWhile: function(match) { - var start = this.pos; - while (this.eat(match)){} - return this.pos > start; - }, - eatSpace: function() { - var start = this.pos; - while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos; - return this.pos > start; - }, - skipToEnd: function() {this.pos = this.string.length;}, - skipTo: function(ch) { - var found = this.string.indexOf(ch, this.pos); - if (found > -1) {this.pos = found; return true;} - }, - backUp: function(n) {this.pos -= n;}, - column: function() { - if (this.lastColumnPos < this.start) { - this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue); - this.lastColumnPos = this.start; - } - return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0); - }, - indentation: function() { - return countColumn(this.string, null, this.tabSize) - - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0); - }, - match: function(pattern, consume, caseInsensitive) { - if (typeof pattern == "string") { - var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;}; - var substr = this.string.substr(this.pos, pattern.length); - if (cased(substr) == cased(pattern)) { - if (consume !== false) this.pos += pattern.length; - return true; - } - } else { - var match = this.string.slice(this.pos).match(pattern); - if (match && match.index > 0) return null; - if (match && consume !== false) this.pos += match[0].length; - return match; - } - }, - current: function(){return this.string.slice(this.start, this.pos);}, - hideFirstChars: function(n, inner) { - this.lineStart += n; - try { return inner(); } - finally { this.lineStart -= n; } - } - }; - - // TEXTMARKERS - - // Created with markText and setBookmark methods. A TextMarker is a - // handle that can be used to clear or find a marked position in the - // document. Line objects hold arrays (markedSpans) containing - // {from, to, marker} object pointing to such marker objects, and - // indicating that such a marker is present on that line. Multiple - // lines may point to the same marker when it spans across lines. - // The spans will have null for their from/to properties when the - // marker continues beyond the start/end of the line. Markers have - // links back to the lines they currently touch. - - var nextMarkerId = 0; - - var TextMarker = CodeMirror.TextMarker = function(doc, type) { - this.lines = []; - this.type = type; - this.doc = doc; - this.id = ++nextMarkerId; - }; - eventMixin(TextMarker); - - // Clear the marker. - TextMarker.prototype.clear = function() { - if (this.explicitlyCleared) return; - var cm = this.doc.cm, withOp = cm && !cm.curOp; - if (withOp) startOperation(cm); - if (hasHandler(this, "clear")) { - var found = this.find(); - if (found) signalLater(this, "clear", found.from, found.to); - } - var min = null, max = null; - for (var i = 0; i < this.lines.length; ++i) { - var line = this.lines[i]; - var span = getMarkedSpanFor(line.markedSpans, this); - if (cm && !this.collapsed) regLineChange(cm, lineNo(line), "text"); - else if (cm) { - if (span.to != null) max = lineNo(line); - if (span.from != null) min = lineNo(line); - } - line.markedSpans = removeMarkedSpan(line.markedSpans, span); - if (span.from == null && this.collapsed && !lineIsHidden(this.doc, line) && cm) - updateLineHeight(line, textHeight(cm.display)); - } - if (cm && this.collapsed && !cm.options.lineWrapping) for (var i = 0; i < this.lines.length; ++i) { - var visual = visualLine(this.lines[i]), len = lineLength(visual); - if (len > cm.display.maxLineLength) { - cm.display.maxLine = visual; - cm.display.maxLineLength = len; - cm.display.maxLineChanged = true; - } - } - - if (min != null && cm && this.collapsed) regChange(cm, min, max + 1); - this.lines.length = 0; - this.explicitlyCleared = true; - if (this.atomic && this.doc.cantEdit) { - this.doc.cantEdit = false; - if (cm) reCheckSelection(cm.doc); - } - if (cm) signalLater(cm, "markerCleared", cm, this); - if (withOp) endOperation(cm); - if (this.parent) this.parent.clear(); - }; - - // Find the position of the marker in the document. Returns a {from, - // to} object by default. Side can be passed to get a specific side - // -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the - // Pos objects returned contain a line object, rather than a line - // number (used to prevent looking up the same line twice). - TextMarker.prototype.find = function(side, lineObj) { - if (side == null && this.type == "bookmark") side = 1; - var from, to; - for (var i = 0; i < this.lines.length; ++i) { - var line = this.lines[i]; - var span = getMarkedSpanFor(line.markedSpans, this); - if (span.from != null) { - from = Pos(lineObj ? line : lineNo(line), span.from); - if (side == -1) return from; - } - if (span.to != null) { - to = Pos(lineObj ? line : lineNo(line), span.to); - if (side == 1) return to; - } - } - return from && {from: from, to: to}; - }; - - // Signals that the marker's widget changed, and surrounding layout - // should be recomputed. - TextMarker.prototype.changed = function() { - var pos = this.find(-1, true), widget = this, cm = this.doc.cm; - if (!pos || !cm) return; - runInOp(cm, function() { - var line = pos.line, lineN = lineNo(pos.line); - var view = findViewForLine(cm, lineN); - if (view) { - clearLineMeasurementCacheFor(view); - cm.curOp.selectionChanged = cm.curOp.forceUpdate = true; - } - cm.curOp.updateMaxLine = true; - if (!lineIsHidden(widget.doc, line) && widget.height != null) { - var oldHeight = widget.height; - widget.height = null; - var dHeight = widgetHeight(widget) - oldHeight; - if (dHeight) - updateLineHeight(line, line.height + dHeight); - } - }); - }; - - TextMarker.prototype.attachLine = function(line) { - if (!this.lines.length && this.doc.cm) { - var op = this.doc.cm.curOp; - if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1) - (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this); - } - this.lines.push(line); - }; - TextMarker.prototype.detachLine = function(line) { - this.lines.splice(indexOf(this.lines, line), 1); - if (!this.lines.length && this.doc.cm) { - var op = this.doc.cm.curOp; - (op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this); - } - }; - - // Collapsed markers have unique ids, in order to be able to order - // them, which is needed for uniquely determining an outer marker - // when they overlap (they may nest, but not partially overlap). - var nextMarkerId = 0; - - // Create a marker, wire it up to the right lines, and - function markText(doc, from, to, options, type) { - // Shared markers (across linked documents) are handled separately - // (markTextShared will call out to this again, once per - // document). - if (options && options.shared) return markTextShared(doc, from, to, options, type); - // Ensure we are in an operation. - if (doc.cm && !doc.cm.curOp) return operation(doc.cm, markText)(doc, from, to, options, type); - - var marker = new TextMarker(doc, type), diff = cmp(from, to); - if (options) copyObj(options, marker, false); - // Don't connect empty markers unless clearWhenEmpty is false - if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false) - return marker; - if (marker.replacedWith) { - // Showing up as a widget implies collapsed (widget replaces text) - marker.collapsed = true; - marker.widgetNode = elt("span", [marker.replacedWith], "CodeMirror-widget"); - if (!options.handleMouseEvents) marker.widgetNode.setAttribute("cm-ignore-events", "true"); - if (options.insertLeft) marker.widgetNode.insertLeft = true; - } - if (marker.collapsed) { - if (conflictingCollapsedRange(doc, from.line, from, to, marker) || - from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker)) - throw new Error("Inserting collapsed marker partially overlapping an existing one"); - sawCollapsedSpans = true; - } - - if (marker.addToHistory) - addChangeToHistory(doc, {from: from, to: to, origin: "markText"}, doc.sel, NaN); - - var curLine = from.line, cm = doc.cm, updateMaxLine; - doc.iter(curLine, to.line + 1, function(line) { - if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine) - updateMaxLine = true; - if (marker.collapsed && curLine != from.line) updateLineHeight(line, 0); - addMarkedSpan(line, new MarkedSpan(marker, - curLine == from.line ? from.ch : null, - curLine == to.line ? to.ch : null)); - ++curLine; - }); - // lineIsHidden depends on the presence of the spans, so needs a second pass - if (marker.collapsed) doc.iter(from.line, to.line + 1, function(line) { - if (lineIsHidden(doc, line)) updateLineHeight(line, 0); - }); - - if (marker.clearOnEnter) on(marker, "beforeCursorEnter", function() { marker.clear(); }); - - if (marker.readOnly) { - sawReadOnlySpans = true; - if (doc.history.done.length || doc.history.undone.length) - doc.clearHistory(); - } - if (marker.collapsed) { - marker.id = ++nextMarkerId; - marker.atomic = true; - } - if (cm) { - // Sync editor state - if (updateMaxLine) cm.curOp.updateMaxLine = true; - if (marker.collapsed) - regChange(cm, from.line, to.line + 1); - else if (marker.className || marker.title || marker.startStyle || marker.endStyle || marker.css) - for (var i = from.line; i <= to.line; i++) regLineChange(cm, i, "text"); - if (marker.atomic) reCheckSelection(cm.doc); - signalLater(cm, "markerAdded", cm, marker); - } - return marker; - } - - // SHARED TEXTMARKERS - - // A shared marker spans multiple linked documents. It is - // implemented as a meta-marker-object controlling multiple normal - // markers. - var SharedTextMarker = CodeMirror.SharedTextMarker = function(markers, primary) { - this.markers = markers; - this.primary = primary; - for (var i = 0; i < markers.length; ++i) - markers[i].parent = this; - }; - eventMixin(SharedTextMarker); - - SharedTextMarker.prototype.clear = function() { - if (this.explicitlyCleared) return; - this.explicitlyCleared = true; - for (var i = 0; i < this.markers.length; ++i) - this.markers[i].clear(); - signalLater(this, "clear"); - }; - SharedTextMarker.prototype.find = function(side, lineObj) { - return this.primary.find(side, lineObj); - }; - - function markTextShared(doc, from, to, options, type) { - options = copyObj(options); - options.shared = false; - var markers = [markText(doc, from, to, options, type)], primary = markers[0]; - var widget = options.widgetNode; - linkedDocs(doc, function(doc) { - if (widget) options.widgetNode = widget.cloneNode(true); - markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type)); - for (var i = 0; i < doc.linked.length; ++i) - if (doc.linked[i].isParent) return; - primary = lst(markers); - }); - return new SharedTextMarker(markers, primary); - } - - function findSharedMarkers(doc) { - return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())), - function(m) { return m.parent; }); - } - - function copySharedMarkers(doc, markers) { - for (var i = 0; i < markers.length; i++) { - var marker = markers[i], pos = marker.find(); - var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to); - if (cmp(mFrom, mTo)) { - var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type); - marker.markers.push(subMark); - subMark.parent = marker; - } - } - } - - function detachSharedMarkers(markers) { - for (var i = 0; i < markers.length; i++) { - var marker = markers[i], linked = [marker.primary.doc];; - linkedDocs(marker.primary.doc, function(d) { linked.push(d); }); - for (var j = 0; j < marker.markers.length; j++) { - var subMarker = marker.markers[j]; - if (indexOf(linked, subMarker.doc) == -1) { - subMarker.parent = null; - marker.markers.splice(j--, 1); - } - } - } - } - - // TEXTMARKER SPANS - - function MarkedSpan(marker, from, to) { - this.marker = marker; - this.from = from; this.to = to; - } - - // Search an array of spans for a span matching the given marker. - function getMarkedSpanFor(spans, marker) { - if (spans) for (var i = 0; i < spans.length; ++i) { - var span = spans[i]; - if (span.marker == marker) return span; - } - } - // Remove a span from an array, returning undefined if no spans are - // left (we don't store arrays for lines without spans). - function removeMarkedSpan(spans, span) { - for (var r, i = 0; i < spans.length; ++i) - if (spans[i] != span) (r || (r = [])).push(spans[i]); - return r; - } - // Add a span to a line. - function addMarkedSpan(line, span) { - line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span]; - span.marker.attachLine(line); - } - - // Used for the algorithm that adjusts markers for a change in the - // document. These functions cut an array of spans at a given - // character position, returning an array of remaining chunks (or - // undefined if nothing remains). - function markedSpansBefore(old, startCh, isInsert) { - if (old) for (var i = 0, nw; i < old.length; ++i) { - var span = old[i], marker = span.marker; - var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh); - if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) { - var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh); - (nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to)); - } - } - return nw; - } - function markedSpansAfter(old, endCh, isInsert) { - if (old) for (var i = 0, nw; i < old.length; ++i) { - var span = old[i], marker = span.marker; - var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh); - if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) { - var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh); - (nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh, - span.to == null ? null : span.to - endCh)); - } - } - return nw; - } - - // Given a change object, compute the new set of marker spans that - // cover the line in which the change took place. Removes spans - // entirely within the change, reconnects spans belonging to the - // same marker that appear on both sides of the change, and cuts off - // spans partially within the change. Returns an array of span - // arrays with one element for each line in (after) the change. - function stretchSpansOverChange(doc, change) { - if (change.full) return null; - var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans; - var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans; - if (!oldFirst && !oldLast) return null; - - var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0; - // Get the spans that 'stick out' on both sides - var first = markedSpansBefore(oldFirst, startCh, isInsert); - var last = markedSpansAfter(oldLast, endCh, isInsert); - - // Next, merge those two ends - var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0); - if (first) { - // Fix up .to properties of first - for (var i = 0; i < first.length; ++i) { - var span = first[i]; - if (span.to == null) { - var found = getMarkedSpanFor(last, span.marker); - if (!found) span.to = startCh; - else if (sameLine) span.to = found.to == null ? null : found.to + offset; - } - } - } - if (last) { - // Fix up .from in last (or move them into first in case of sameLine) - for (var i = 0; i < last.length; ++i) { - var span = last[i]; - if (span.to != null) span.to += offset; - if (span.from == null) { - var found = getMarkedSpanFor(first, span.marker); - if (!found) { - span.from = offset; - if (sameLine) (first || (first = [])).push(span); - } - } else { - span.from += offset; - if (sameLine) (first || (first = [])).push(span); - } - } - } - // Make sure we didn't create any zero-length spans - if (first) first = clearEmptySpans(first); - if (last && last != first) last = clearEmptySpans(last); - - var newMarkers = [first]; - if (!sameLine) { - // Fill gap with whole-line-spans - var gap = change.text.length - 2, gapMarkers; - if (gap > 0 && first) - for (var i = 0; i < first.length; ++i) - if (first[i].to == null) - (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i].marker, null, null)); - for (var i = 0; i < gap; ++i) - newMarkers.push(gapMarkers); - newMarkers.push(last); - } - return newMarkers; - } - - // Remove spans that are empty and don't have a clearWhenEmpty - // option of false. - function clearEmptySpans(spans) { - for (var i = 0; i < spans.length; ++i) { - var span = spans[i]; - if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false) - spans.splice(i--, 1); - } - if (!spans.length) return null; - return spans; - } - - // Used for un/re-doing changes from the history. Combines the - // result of computing the existing spans with the set of spans that - // existed in the history (so that deleting around a span and then - // undoing brings back the span). - function mergeOldSpans(doc, change) { - var old = getOldSpans(doc, change); - var stretched = stretchSpansOverChange(doc, change); - if (!old) return stretched; - if (!stretched) return old; - - for (var i = 0; i < old.length; ++i) { - var oldCur = old[i], stretchCur = stretched[i]; - if (oldCur && stretchCur) { - spans: for (var j = 0; j < stretchCur.length; ++j) { - var span = stretchCur[j]; - for (var k = 0; k < oldCur.length; ++k) - if (oldCur[k].marker == span.marker) continue spans; - oldCur.push(span); - } - } else if (stretchCur) { - old[i] = stretchCur; - } - } - return old; - } - - // Used to 'clip' out readOnly ranges when making a change. - function removeReadOnlyRanges(doc, from, to) { - var markers = null; - doc.iter(from.line, to.line + 1, function(line) { - if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) { - var mark = line.markedSpans[i].marker; - if (mark.readOnly && (!markers || indexOf(markers, mark) == -1)) - (markers || (markers = [])).push(mark); - } - }); - if (!markers) return null; - var parts = [{from: from, to: to}]; - for (var i = 0; i < markers.length; ++i) { - var mk = markers[i], m = mk.find(0); - for (var j = 0; j < parts.length; ++j) { - var p = parts[j]; - if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) continue; - var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to); - if (dfrom < 0 || !mk.inclusiveLeft && !dfrom) - newParts.push({from: p.from, to: m.from}); - if (dto > 0 || !mk.inclusiveRight && !dto) - newParts.push({from: m.to, to: p.to}); - parts.splice.apply(parts, newParts); - j += newParts.length - 1; - } - } - return parts; - } - - // Connect or disconnect spans from a line. - function detachMarkedSpans(line) { - var spans = line.markedSpans; - if (!spans) return; - for (var i = 0; i < spans.length; ++i) - spans[i].marker.detachLine(line); - line.markedSpans = null; - } - function attachMarkedSpans(line, spans) { - if (!spans) return; - for (var i = 0; i < spans.length; ++i) - spans[i].marker.attachLine(line); - line.markedSpans = spans; - } - - // Helpers used when computing which overlapping collapsed span - // counts as the larger one. - function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0; } - function extraRight(marker) { return marker.inclusiveRight ? 1 : 0; } - - // Returns a number indicating which of two overlapping collapsed - // spans is larger (and thus includes the other). Falls back to - // comparing ids when the spans cover exactly the same range. - function compareCollapsedMarkers(a, b) { - var lenDiff = a.lines.length - b.lines.length; - if (lenDiff != 0) return lenDiff; - var aPos = a.find(), bPos = b.find(); - var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b); - if (fromCmp) return -fromCmp; - var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b); - if (toCmp) return toCmp; - return b.id - a.id; - } - - // Find out whether a line ends or starts in a collapsed span. If - // so, return the marker for that span. - function collapsedSpanAtSide(line, start) { - var sps = sawCollapsedSpans && line.markedSpans, found; - if (sps) for (var sp, i = 0; i < sps.length; ++i) { - sp = sps[i]; - if (sp.marker.collapsed && (start ? sp.from : sp.to) == null && - (!found || compareCollapsedMarkers(found, sp.marker) < 0)) - found = sp.marker; - } - return found; - } - function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true); } - function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false); } - - // Test whether there exists a collapsed span that partially - // overlaps (covers the start or end, but not both) of a new span. - // Such overlap is not allowed. - function conflictingCollapsedRange(doc, lineNo, from, to, marker) { - var line = getLine(doc, lineNo); - var sps = sawCollapsedSpans && line.markedSpans; - if (sps) for (var i = 0; i < sps.length; ++i) { - var sp = sps[i]; - if (!sp.marker.collapsed) continue; - var found = sp.marker.find(0); - var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker); - var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker); - if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) continue; - if (fromCmp <= 0 && (cmp(found.to, from) > 0 || (sp.marker.inclusiveRight && marker.inclusiveLeft)) || - fromCmp >= 0 && (cmp(found.from, to) < 0 || (sp.marker.inclusiveLeft && marker.inclusiveRight))) - return true; - } - } - - // A visual line is a line as drawn on the screen. Folding, for - // example, can cause multiple logical lines to appear on the same - // visual line. This finds the start of the visual line that the - // given line is part of (usually that is the line itself). - function visualLine(line) { - var merged; - while (merged = collapsedSpanAtStart(line)) - line = merged.find(-1, true).line; - return line; - } - - // Returns an array of logical lines that continue the visual line - // started by the argument, or undefined if there are no such lines. - function visualLineContinued(line) { - var merged, lines; - while (merged = collapsedSpanAtEnd(line)) { - line = merged.find(1, true).line; - (lines || (lines = [])).push(line); - } - return lines; - } - - // Get the line number of the start of the visual line that the - // given line number is part of. - function visualLineNo(doc, lineN) { - var line = getLine(doc, lineN), vis = visualLine(line); - if (line == vis) return lineN; - return lineNo(vis); - } - // Get the line number of the start of the next visual line after - // the given line. - function visualLineEndNo(doc, lineN) { - if (lineN > doc.lastLine()) return lineN; - var line = getLine(doc, lineN), merged; - if (!lineIsHidden(doc, line)) return lineN; - while (merged = collapsedSpanAtEnd(line)) - line = merged.find(1, true).line; - return lineNo(line) + 1; - } - - // Compute whether a line is hidden. Lines count as hidden when they - // are part of a visual line that starts with another line, or when - // they are entirely covered by collapsed, non-widget span. - function lineIsHidden(doc, line) { - var sps = sawCollapsedSpans && line.markedSpans; - if (sps) for (var sp, i = 0; i < sps.length; ++i) { - sp = sps[i]; - if (!sp.marker.collapsed) continue; - if (sp.from == null) return true; - if (sp.marker.widgetNode) continue; - if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp)) - return true; - } - } - function lineIsHiddenInner(doc, line, span) { - if (span.to == null) { - var end = span.marker.find(1, true); - return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker)); - } - if (span.marker.inclusiveRight && span.to == line.text.length) - return true; - for (var sp, i = 0; i < line.markedSpans.length; ++i) { - sp = line.markedSpans[i]; - if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to && - (sp.to == null || sp.to != span.from) && - (sp.marker.inclusiveLeft || span.marker.inclusiveRight) && - lineIsHiddenInner(doc, line, sp)) return true; - } - } - - // LINE WIDGETS - - // Line widgets are block elements displayed above or below a line. - - var LineWidget = CodeMirror.LineWidget = function(doc, node, options) { - if (options) for (var opt in options) if (options.hasOwnProperty(opt)) - this[opt] = options[opt]; - this.doc = doc; - this.node = node; - }; - eventMixin(LineWidget); - - function adjustScrollWhenAboveVisible(cm, line, diff) { - if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop)) - addToScrollPos(cm, null, diff); - } - - LineWidget.prototype.clear = function() { - var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line); - if (no == null || !ws) return; - for (var i = 0; i < ws.length; ++i) if (ws[i] == this) ws.splice(i--, 1); - if (!ws.length) line.widgets = null; - var height = widgetHeight(this); - updateLineHeight(line, Math.max(0, line.height - height)); - if (cm) runInOp(cm, function() { - adjustScrollWhenAboveVisible(cm, line, -height); - regLineChange(cm, no, "widget"); - }); - }; - LineWidget.prototype.changed = function() { - var oldH = this.height, cm = this.doc.cm, line = this.line; - this.height = null; - var diff = widgetHeight(this) - oldH; - if (!diff) return; - updateLineHeight(line, line.height + diff); - if (cm) runInOp(cm, function() { - cm.curOp.forceUpdate = true; - adjustScrollWhenAboveVisible(cm, line, diff); - }); - }; - - function widgetHeight(widget) { - if (widget.height != null) return widget.height; - var cm = widget.doc.cm; - if (!cm) return 0; - if (!contains(document.body, widget.node)) { - var parentStyle = "position: relative;"; - if (widget.coverGutter) - parentStyle += "margin-left: -" + cm.display.gutters.offsetWidth + "px;"; - if (widget.noHScroll) - parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;"; - removeChildrenAndAdd(cm.display.measure, elt("div", [widget.node], null, parentStyle)); - } - return widget.height = widget.node.parentNode.offsetHeight; - } - - function addLineWidget(doc, handle, node, options) { - var widget = new LineWidget(doc, node, options); - var cm = doc.cm; - if (cm && widget.noHScroll) cm.display.alignWidgets = true; - changeLine(doc, handle, "widget", function(line) { - var widgets = line.widgets || (line.widgets = []); - if (widget.insertAt == null) widgets.push(widget); - else widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget); - widget.line = line; - if (cm && !lineIsHidden(doc, line)) { - var aboveVisible = heightAtLine(line) < doc.scrollTop; - updateLineHeight(line, line.height + widgetHeight(widget)); - if (aboveVisible) addToScrollPos(cm, null, widget.height); - cm.curOp.forceUpdate = true; - } - return true; - }); - return widget; - } - - // LINE DATA STRUCTURE - - // Line objects. These hold state related to a line, including - // highlighting info (the styles array). - var Line = CodeMirror.Line = function(text, markedSpans, estimateHeight) { - this.text = text; - attachMarkedSpans(this, markedSpans); - this.height = estimateHeight ? estimateHeight(this) : 1; - }; - eventMixin(Line); - Line.prototype.lineNo = function() { return lineNo(this); }; - - // Change the content (text, markers) of a line. Automatically - // invalidates cached information and tries to re-estimate the - // line's height. - function updateLine(line, text, markedSpans, estimateHeight) { - line.text = text; - if (line.stateAfter) line.stateAfter = null; - if (line.styles) line.styles = null; - if (line.order != null) line.order = null; - detachMarkedSpans(line); - attachMarkedSpans(line, markedSpans); - var estHeight = estimateHeight ? estimateHeight(line) : 1; - if (estHeight != line.height) updateLineHeight(line, estHeight); - } - - // Detach a line from the document tree and its markers. - function cleanUpLine(line) { - line.parent = null; - detachMarkedSpans(line); - } - - function extractLineClasses(type, output) { - if (type) for (;;) { - var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/); - if (!lineClass) break; - type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length); - var prop = lineClass[1] ? "bgClass" : "textClass"; - if (output[prop] == null) - output[prop] = lineClass[2]; - else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(output[prop])) - output[prop] += " " + lineClass[2]; - } - return type; - } - - function callBlankLine(mode, state) { - if (mode.blankLine) return mode.blankLine(state); - if (!mode.innerMode) return; - var inner = CodeMirror.innerMode(mode, state); - if (inner.mode.blankLine) return inner.mode.blankLine(inner.state); - } - - function readToken(mode, stream, state, inner) { - for (var i = 0; i < 10; i++) { - if (inner) inner[0] = CodeMirror.innerMode(mode, state).mode; - var style = mode.token(stream, state); - if (stream.pos > stream.start) return style; - } - throw new Error("Mode " + mode.name + " failed to advance stream."); - } - - // Utility for getTokenAt and getLineTokens - function takeToken(cm, pos, precise, asArray) { - function getObj(copy) { - return {start: stream.start, end: stream.pos, - string: stream.current(), - type: style || null, - state: copy ? copyState(doc.mode, state) : state}; - } - - var doc = cm.doc, mode = doc.mode, style; - pos = clipPos(doc, pos); - var line = getLine(doc, pos.line), state = getStateBefore(cm, pos.line, precise); - var stream = new StringStream(line.text, cm.options.tabSize), tokens; - if (asArray) tokens = []; - while ((asArray || stream.pos < pos.ch) && !stream.eol()) { - stream.start = stream.pos; - style = readToken(mode, stream, state); - if (asArray) tokens.push(getObj(true)); - } - return asArray ? tokens : getObj(); - } - - // Run the given mode's parser over a line, calling f for each token. - function runMode(cm, text, mode, state, f, lineClasses, forceToEnd) { - var flattenSpans = mode.flattenSpans; - if (flattenSpans == null) flattenSpans = cm.options.flattenSpans; - var curStart = 0, curStyle = null; - var stream = new StringStream(text, cm.options.tabSize), style; - var inner = cm.options.addModeClass && [null]; - if (text == "") extractLineClasses(callBlankLine(mode, state), lineClasses); - while (!stream.eol()) { - if (stream.pos > cm.options.maxHighlightLength) { - flattenSpans = false; - if (forceToEnd) processLine(cm, text, state, stream.pos); - stream.pos = text.length; - style = null; - } else { - style = extractLineClasses(readToken(mode, stream, state, inner), lineClasses); - } - if (inner) { - var mName = inner[0].name; - if (mName) style = "m-" + (style ? mName + " " + style : mName); - } - if (!flattenSpans || curStyle != style) { - while (curStart < stream.start) { - curStart = Math.min(stream.start, curStart + 50000); - f(curStart, curStyle); - } - curStyle = style; - } - stream.start = stream.pos; - } - while (curStart < stream.pos) { - // Webkit seems to refuse to render text nodes longer than 57444 characters - var pos = Math.min(stream.pos, curStart + 50000); - f(pos, curStyle); - curStart = pos; - } - } - - // Compute a style array (an array starting with a mode generation - // -- for invalidation -- followed by pairs of end positions and - // style strings), which is used to highlight the tokens on the - // line. - function highlightLine(cm, line, state, forceToEnd) { - // A styles array always starts with a number identifying the - // mode/overlays that it is based on (for easy invalidation). - var st = [cm.state.modeGen], lineClasses = {}; - // Compute the base array of styles - runMode(cm, line.text, cm.doc.mode, state, function(end, style) { - st.push(end, style); - }, lineClasses, forceToEnd); - - // Run overlays, adjust style array. - for (var o = 0; o < cm.state.overlays.length; ++o) { - var overlay = cm.state.overlays[o], i = 1, at = 0; - runMode(cm, line.text, overlay.mode, true, function(end, style) { - var start = i; - // Ensure there's a token end at the current position, and that i points at it - while (at < end) { - var i_end = st[i]; - if (i_end > end) - st.splice(i, 1, end, st[i+1], i_end); - i += 2; - at = Math.min(end, i_end); - } - if (!style) return; - if (overlay.opaque) { - st.splice(start, i - start, end, "cm-overlay " + style); - i = start + 2; - } else { - for (; start < i; start += 2) { - var cur = st[start+1]; - st[start+1] = (cur ? cur + " " : "") + "cm-overlay " + style; - } - } - }, lineClasses); - } - - return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null}; - } - - function getLineStyles(cm, line, updateFrontier) { - if (!line.styles || line.styles[0] != cm.state.modeGen) { - var state = getStateBefore(cm, lineNo(line)); - var result = highlightLine(cm, line, line.text.length > cm.options.maxHighlightLength ? copyState(cm.doc.mode, state) : state); - line.stateAfter = state; - line.styles = result.styles; - if (result.classes) line.styleClasses = result.classes; - else if (line.styleClasses) line.styleClasses = null; - if (updateFrontier === cm.doc.frontier) cm.doc.frontier++; - } - return line.styles; - } - - // Lightweight form of highlight -- proceed over this line and - // update state, but don't save a style array. Used for lines that - // aren't currently visible. - function processLine(cm, text, state, startAt) { - var mode = cm.doc.mode; - var stream = new StringStream(text, cm.options.tabSize); - stream.start = stream.pos = startAt || 0; - if (text == "") callBlankLine(mode, state); - while (!stream.eol()) { - readToken(mode, stream, state); - stream.start = stream.pos; - } - } - - // Convert a style as returned by a mode (either null, or a string - // containing one or more styles) to a CSS style. This is cached, - // and also looks for line-wide styles. - var styleToClassCache = {}, styleToClassCacheWithMode = {}; - function interpretTokenStyle(style, options) { - if (!style || /^\s*$/.test(style)) return null; - var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache; - return cache[style] || - (cache[style] = style.replace(/\S+/g, "cm-$&")); - } - - // Render the DOM representation of the text of a line. Also builds - // up a 'line map', which points at the DOM nodes that represent - // specific stretches of text, and is used by the measuring code. - // The returned object contains the DOM node, this map, and - // information about line-wide styles that were set by the mode. - function buildLineContent(cm, lineView) { - // The padding-right forces the element to have a 'border', which - // is needed on Webkit to be able to get line-level bounding - // rectangles for it (in measureChar). - var content = elt("span", null, null, webkit ? "padding-right: .1px" : null); - var builder = {pre: elt("pre", [content], "CodeMirror-line"), content: content, - col: 0, pos: 0, cm: cm, - splitSpaces: (ie || webkit) && cm.getOption("lineWrapping")}; - lineView.measure = {}; - - // Iterate over the logical lines that make up this visual line. - for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) { - var line = i ? lineView.rest[i - 1] : lineView.line, order; - builder.pos = 0; - builder.addToken = buildToken; - // Optionally wire in some hacks into the token-rendering - // algorithm, to deal with browser quirks. - if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line))) - builder.addToken = buildTokenBadBidi(builder.addToken, order); - builder.map = []; - var allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line); - insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate)); - if (line.styleClasses) { - if (line.styleClasses.bgClass) - builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || ""); - if (line.styleClasses.textClass) - builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || ""); - } - - // Ensure at least a single node is present, for measuring. - if (builder.map.length == 0) - builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure))); - - // Store the map and a cache object for the current logical line - if (i == 0) { - lineView.measure.map = builder.map; - lineView.measure.cache = {}; - } else { - (lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map); - (lineView.measure.caches || (lineView.measure.caches = [])).push({}); - } - } - - // See issue #2901 - if (webkit && /\bcm-tab\b/.test(builder.content.lastChild.className)) - builder.content.className = "cm-tab-wrap-hack"; - - signal(cm, "renderLine", cm, lineView.line, builder.pre); - if (builder.pre.className) - builder.textClass = joinClasses(builder.pre.className, builder.textClass || ""); - - return builder; - } - - function defaultSpecialCharPlaceholder(ch) { - var token = elt("span", "\u2022", "cm-invalidchar"); - token.title = "\\u" + ch.charCodeAt(0).toString(16); - token.setAttribute("aria-label", token.title); - return token; - } - - // Build up the DOM representation for a single token, and add it to - // the line map. Takes care to render special characters separately. - function buildToken(builder, text, style, startStyle, endStyle, title, css) { - if (!text) return; - var displayText = builder.splitSpaces ? text.replace(/ {3,}/g, splitSpaces) : text; - var special = builder.cm.state.specialChars, mustWrap = false; - if (!special.test(text)) { - builder.col += text.length; - var content = document.createTextNode(displayText); - builder.map.push(builder.pos, builder.pos + text.length, content); - if (ie && ie_version < 9) mustWrap = true; - builder.pos += text.length; - } else { - var content = document.createDocumentFragment(), pos = 0; - while (true) { - special.lastIndex = pos; - var m = special.exec(text); - var skipped = m ? m.index - pos : text.length - pos; - if (skipped) { - var txt = document.createTextNode(displayText.slice(pos, pos + skipped)); - if (ie && ie_version < 9) content.appendChild(elt("span", [txt])); - else content.appendChild(txt); - builder.map.push(builder.pos, builder.pos + skipped, txt); - builder.col += skipped; - builder.pos += skipped; - } - if (!m) break; - pos += skipped + 1; - if (m[0] == "\t") { - var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize; - var txt = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab")); - txt.setAttribute("role", "presentation"); - txt.setAttribute("cm-text", "\t"); - builder.col += tabWidth; - } else if (m[0] == "\r" || m[0] == "\n") { - var txt = content.appendChild(elt("span", m[0] == "\r" ? "\u240d" : "\u2424", "cm-invalidchar")); - txt.setAttribute("cm-text", m[0]); - builder.col += 1; - } else { - var txt = builder.cm.options.specialCharPlaceholder(m[0]); - txt.setAttribute("cm-text", m[0]); - if (ie && ie_version < 9) content.appendChild(elt("span", [txt])); - else content.appendChild(txt); - builder.col += 1; - } - builder.map.push(builder.pos, builder.pos + 1, txt); - builder.pos++; - } - } - if (style || startStyle || endStyle || mustWrap || css) { - var fullStyle = style || ""; - if (startStyle) fullStyle += startStyle; - if (endStyle) fullStyle += endStyle; - var token = elt("span", [content], fullStyle, css); - if (title) token.title = title; - return builder.content.appendChild(token); - } - builder.content.appendChild(content); - } - - function splitSpaces(old) { - var out = " "; - for (var i = 0; i < old.length - 2; ++i) out += i % 2 ? " " : "\u00a0"; - out += " "; - return out; - } - - // Work around nonsense dimensions being reported for stretches of - // right-to-left text. - function buildTokenBadBidi(inner, order) { - return function(builder, text, style, startStyle, endStyle, title, css) { - style = style ? style + " cm-force-border" : "cm-force-border"; - var start = builder.pos, end = start + text.length; - for (;;) { - // Find the part that overlaps with the start of this text - for (var i = 0; i < order.length; i++) { - var part = order[i]; - if (part.to > start && part.from <= start) break; - } - if (part.to >= end) return inner(builder, text, style, startStyle, endStyle, title, css); - inner(builder, text.slice(0, part.to - start), style, startStyle, null, title, css); - startStyle = null; - text = text.slice(part.to - start); - start = part.to; - } - }; - } - - function buildCollapsedSpan(builder, size, marker, ignoreWidget) { - var widget = !ignoreWidget && marker.widgetNode; - if (widget) builder.map.push(builder.pos, builder.pos + size, widget); - if (!ignoreWidget && builder.cm.display.input.needsContentAttribute) { - if (!widget) - widget = builder.content.appendChild(document.createElement("span")); - widget.setAttribute("cm-marker", marker.id); - } - if (widget) { - builder.cm.display.input.setUneditable(widget); - builder.content.appendChild(widget); - } - builder.pos += size; - } - - // Outputs a number of spans to make up a line, taking highlighting - // and marked text into account. - function insertLineContent(line, builder, styles) { - var spans = line.markedSpans, allText = line.text, at = 0; - if (!spans) { - for (var i = 1; i < styles.length; i+=2) - builder.addToken(builder, allText.slice(at, at = styles[i]), interpretTokenStyle(styles[i+1], builder.cm.options)); - return; - } - - var len = allText.length, pos = 0, i = 1, text = "", style, css; - var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed; - for (;;) { - if (nextChange == pos) { // Update current marker set - spanStyle = spanEndStyle = spanStartStyle = title = css = ""; - collapsed = null; nextChange = Infinity; - var foundBookmarks = [], endStyles - for (var j = 0; j < spans.length; ++j) { - var sp = spans[j], m = sp.marker; - if (m.type == "bookmark" && sp.from == pos && m.widgetNode) { - foundBookmarks.push(m); - } else if (sp.from <= pos && (sp.to == null || sp.to > pos || m.collapsed && sp.to == pos && sp.from == pos)) { - if (sp.to != null && sp.to != pos && nextChange > sp.to) { - nextChange = sp.to; - spanEndStyle = ""; - } - if (m.className) spanStyle += " " + m.className; - if (m.css) css = (css ? css + ";" : "") + m.css; - if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle; - if (m.endStyle && sp.to == nextChange) (endStyles || (endStyles = [])).push(m.endStyle, sp.to) - if (m.title && !title) title = m.title; - if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0)) - collapsed = sp; - } else if (sp.from > pos && nextChange > sp.from) { - nextChange = sp.from; - } - } - if (endStyles) for (var j = 0; j < endStyles.length; j += 2) - if (endStyles[j + 1] == nextChange) spanEndStyle += " " + endStyles[j] - - if (!collapsed || collapsed.from == pos) for (var j = 0; j < foundBookmarks.length; ++j) - buildCollapsedSpan(builder, 0, foundBookmarks[j]); - if (collapsed && (collapsed.from || 0) == pos) { - buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos, - collapsed.marker, collapsed.from == null); - if (collapsed.to == null) return; - if (collapsed.to == pos) collapsed = false; - } - } - if (pos >= len) break; - - var upto = Math.min(len, nextChange); - while (true) { - if (text) { - var end = pos + text.length; - if (!collapsed) { - var tokenText = end > upto ? text.slice(0, upto - pos) : text; - builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle, - spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title, css); - } - if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;} - pos = end; - spanStartStyle = ""; - } - text = allText.slice(at, at = styles[i++]); - style = interpretTokenStyle(styles[i++], builder.cm.options); - } - } - } - - // DOCUMENT DATA STRUCTURE - - // By default, updates that start and end at the beginning of a line - // are treated specially, in order to make the association of line - // widgets and marker elements with the text behave more intuitive. - function isWholeLineUpdate(doc, change) { - return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == "" && - (!doc.cm || doc.cm.options.wholeLineUpdateBefore); - } - - // Perform a change on the document data structure. - function updateDoc(doc, change, markedSpans, estimateHeight) { - function spansFor(n) {return markedSpans ? markedSpans[n] : null;} - function update(line, text, spans) { - updateLine(line, text, spans, estimateHeight); - signalLater(line, "change", line, change); - } - function linesFor(start, end) { - for (var i = start, result = []; i < end; ++i) - result.push(new Line(text[i], spansFor(i), estimateHeight)); - return result; - } - - var from = change.from, to = change.to, text = change.text; - var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line); - var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line; - - // Adjust the line structure - if (change.full) { - doc.insert(0, linesFor(0, text.length)); - doc.remove(text.length, doc.size - text.length); - } else if (isWholeLineUpdate(doc, change)) { - // This is a whole-line replace. Treated specially to make - // sure line objects move the way they are supposed to. - var added = linesFor(0, text.length - 1); - update(lastLine, lastLine.text, lastSpans); - if (nlines) doc.remove(from.line, nlines); - if (added.length) doc.insert(from.line, added); - } else if (firstLine == lastLine) { - if (text.length == 1) { - update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans); - } else { - var added = linesFor(1, text.length - 1); - added.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight)); - update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)); - doc.insert(from.line + 1, added); - } - } else if (text.length == 1) { - update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0)); - doc.remove(from.line + 1, nlines); - } else { - update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)); - update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans); - var added = linesFor(1, text.length - 1); - if (nlines > 1) doc.remove(from.line + 1, nlines - 1); - doc.insert(from.line + 1, added); - } - - signalLater(doc, "change", doc, change); - } - - // The document is represented as a BTree consisting of leaves, with - // chunk of lines in them, and branches, with up to ten leaves or - // other branch nodes below them. The top node is always a branch - // node, and is the document object itself (meaning it has - // additional methods and properties). - // - // All nodes have parent links. The tree is used both to go from - // line numbers to line objects, and to go from objects to numbers. - // It also indexes by height, and is used to convert between height - // and line object, and to find the total height of the document. - // - // See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html - - function LeafChunk(lines) { - this.lines = lines; - this.parent = null; - for (var i = 0, height = 0; i < lines.length; ++i) { - lines[i].parent = this; - height += lines[i].height; - } - this.height = height; - } - - LeafChunk.prototype = { - chunkSize: function() { return this.lines.length; }, - // Remove the n lines at offset 'at'. - removeInner: function(at, n) { - for (var i = at, e = at + n; i < e; ++i) { - var line = this.lines[i]; - this.height -= line.height; - cleanUpLine(line); - signalLater(line, "delete"); - } - this.lines.splice(at, n); - }, - // Helper used to collapse a small branch into a single leaf. - collapse: function(lines) { - lines.push.apply(lines, this.lines); - }, - // Insert the given array of lines at offset 'at', count them as - // having the given height. - insertInner: function(at, lines, height) { - this.height += height; - this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at)); - for (var i = 0; i < lines.length; ++i) lines[i].parent = this; - }, - // Used to iterate over a part of the tree. - iterN: function(at, n, op) { - for (var e = at + n; at < e; ++at) - if (op(this.lines[at])) return true; - } - }; - - function BranchChunk(children) { - this.children = children; - var size = 0, height = 0; - for (var i = 0; i < children.length; ++i) { - var ch = children[i]; - size += ch.chunkSize(); height += ch.height; - ch.parent = this; - } - this.size = size; - this.height = height; - this.parent = null; - } - - BranchChunk.prototype = { - chunkSize: function() { return this.size; }, - removeInner: function(at, n) { - this.size -= n; - for (var i = 0; i < this.children.length; ++i) { - var child = this.children[i], sz = child.chunkSize(); - if (at < sz) { - var rm = Math.min(n, sz - at), oldHeight = child.height; - child.removeInner(at, rm); - this.height -= oldHeight - child.height; - if (sz == rm) { this.children.splice(i--, 1); child.parent = null; } - if ((n -= rm) == 0) break; - at = 0; - } else at -= sz; - } - // If the result is smaller than 25 lines, ensure that it is a - // single leaf node. - if (this.size - n < 25 && - (this.children.length > 1 || !(this.children[0] instanceof LeafChunk))) { - var lines = []; - this.collapse(lines); - this.children = [new LeafChunk(lines)]; - this.children[0].parent = this; - } - }, - collapse: function(lines) { - for (var i = 0; i < this.children.length; ++i) this.children[i].collapse(lines); - }, - insertInner: function(at, lines, height) { - this.size += lines.length; - this.height += height; - for (var i = 0; i < this.children.length; ++i) { - var child = this.children[i], sz = child.chunkSize(); - if (at <= sz) { - child.insertInner(at, lines, height); - if (child.lines && child.lines.length > 50) { - while (child.lines.length > 50) { - var spilled = child.lines.splice(child.lines.length - 25, 25); - var newleaf = new LeafChunk(spilled); - child.height -= newleaf.height; - this.children.splice(i + 1, 0, newleaf); - newleaf.parent = this; - } - this.maybeSpill(); - } - break; - } - at -= sz; - } - }, - // When a node has grown, check whether it should be split. - maybeSpill: function() { - if (this.children.length <= 10) return; - var me = this; - do { - var spilled = me.children.splice(me.children.length - 5, 5); - var sibling = new BranchChunk(spilled); - if (!me.parent) { // Become the parent node - var copy = new BranchChunk(me.children); - copy.parent = me; - me.children = [copy, sibling]; - me = copy; - } else { - me.size -= sibling.size; - me.height -= sibling.height; - var myIndex = indexOf(me.parent.children, me); - me.parent.children.splice(myIndex + 1, 0, sibling); - } - sibling.parent = me.parent; - } while (me.children.length > 10); - me.parent.maybeSpill(); - }, - iterN: function(at, n, op) { - for (var i = 0; i < this.children.length; ++i) { - var child = this.children[i], sz = child.chunkSize(); - if (at < sz) { - var used = Math.min(n, sz - at); - if (child.iterN(at, used, op)) return true; - if ((n -= used) == 0) break; - at = 0; - } else at -= sz; - } - } - }; - - var nextDocId = 0; - var Doc = CodeMirror.Doc = function(text, mode, firstLine, lineSep) { - if (!(this instanceof Doc)) return new Doc(text, mode, firstLine, lineSep); - if (firstLine == null) firstLine = 0; - - BranchChunk.call(this, [new LeafChunk([new Line("", null)])]); - this.first = firstLine; - this.scrollTop = this.scrollLeft = 0; - this.cantEdit = false; - this.cleanGeneration = 1; - this.frontier = firstLine; - var start = Pos(firstLine, 0); - this.sel = simpleSelection(start); - this.history = new History(null); - this.id = ++nextDocId; - this.modeOption = mode; - this.lineSep = lineSep; - this.extend = false; - - if (typeof text == "string") text = this.splitLines(text); - updateDoc(this, {from: start, to: start, text: text}); - setSelection(this, simpleSelection(start), sel_dontScroll); - }; - - Doc.prototype = createObj(BranchChunk.prototype, { - constructor: Doc, - // Iterate over the document. Supports two forms -- with only one - // argument, it calls that for each line in the document. With - // three, it iterates over the range given by the first two (with - // the second being non-inclusive). - iter: function(from, to, op) { - if (op) this.iterN(from - this.first, to - from, op); - else this.iterN(this.first, this.first + this.size, from); - }, - - // Non-public interface for adding and removing lines. - insert: function(at, lines) { - var height = 0; - for (var i = 0; i < lines.length; ++i) height += lines[i].height; - this.insertInner(at - this.first, lines, height); - }, - remove: function(at, n) { this.removeInner(at - this.first, n); }, - - // From here, the methods are part of the public interface. Most - // are also available from CodeMirror (editor) instances. - - getValue: function(lineSep) { - var lines = getLines(this, this.first, this.first + this.size); - if (lineSep === false) return lines; - return lines.join(lineSep || this.lineSeparator()); - }, - setValue: docMethodOp(function(code) { - var top = Pos(this.first, 0), last = this.first + this.size - 1; - makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length), - text: this.splitLines(code), origin: "setValue", full: true}, true); - setSelection(this, simpleSelection(top)); - }), - replaceRange: function(code, from, to, origin) { - from = clipPos(this, from); - to = to ? clipPos(this, to) : from; - replaceRange(this, code, from, to, origin); - }, - getRange: function(from, to, lineSep) { - var lines = getBetween(this, clipPos(this, from), clipPos(this, to)); - if (lineSep === false) return lines; - return lines.join(lineSep || this.lineSeparator()); - }, - - getLine: function(line) {var l = this.getLineHandle(line); return l && l.text;}, - - getLineHandle: function(line) {if (isLine(this, line)) return getLine(this, line);}, - getLineNumber: function(line) {return lineNo(line);}, - - getLineHandleVisualStart: function(line) { - if (typeof line == "number") line = getLine(this, line); - return visualLine(line); - }, - - lineCount: function() {return this.size;}, - firstLine: function() {return this.first;}, - lastLine: function() {return this.first + this.size - 1;}, - - clipPos: function(pos) {return clipPos(this, pos);}, - - getCursor: function(start) { - var range = this.sel.primary(), pos; - if (start == null || start == "head") pos = range.head; - else if (start == "anchor") pos = range.anchor; - else if (start == "end" || start == "to" || start === false) pos = range.to(); - else pos = range.from(); - return pos; - }, - listSelections: function() { return this.sel.ranges; }, - somethingSelected: function() {return this.sel.somethingSelected();}, - - setCursor: docMethodOp(function(line, ch, options) { - setSimpleSelection(this, clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line), null, options); - }), - setSelection: docMethodOp(function(anchor, head, options) { - setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options); - }), - extendSelection: docMethodOp(function(head, other, options) { - extendSelection(this, clipPos(this, head), other && clipPos(this, other), options); - }), - extendSelections: docMethodOp(function(heads, options) { - extendSelections(this, clipPosArray(this, heads), options); - }), - extendSelectionsBy: docMethodOp(function(f, options) { - var heads = map(this.sel.ranges, f); - extendSelections(this, clipPosArray(this, heads), options); - }), - setSelections: docMethodOp(function(ranges, primary, options) { - if (!ranges.length) return; - for (var i = 0, out = []; i < ranges.length; i++) - out[i] = new Range(clipPos(this, ranges[i].anchor), - clipPos(this, ranges[i].head)); - if (primary == null) primary = Math.min(ranges.length - 1, this.sel.primIndex); - setSelection(this, normalizeSelection(out, primary), options); - }), - addSelection: docMethodOp(function(anchor, head, options) { - var ranges = this.sel.ranges.slice(0); - ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor))); - setSelection(this, normalizeSelection(ranges, ranges.length - 1), options); - }), - - getSelection: function(lineSep) { - var ranges = this.sel.ranges, lines; - for (var i = 0; i < ranges.length; i++) { - var sel = getBetween(this, ranges[i].from(), ranges[i].to()); - lines = lines ? lines.concat(sel) : sel; - } - if (lineSep === false) return lines; - else return lines.join(lineSep || this.lineSeparator()); - }, - getSelections: function(lineSep) { - var parts = [], ranges = this.sel.ranges; - for (var i = 0; i < ranges.length; i++) { - var sel = getBetween(this, ranges[i].from(), ranges[i].to()); - if (lineSep !== false) sel = sel.join(lineSep || this.lineSeparator()); - parts[i] = sel; - } - return parts; - }, - replaceSelection: function(code, collapse, origin) { - var dup = []; - for (var i = 0; i < this.sel.ranges.length; i++) - dup[i] = code; - this.replaceSelections(dup, collapse, origin || "+input"); - }, - replaceSelections: docMethodOp(function(code, collapse, origin) { - var changes = [], sel = this.sel; - for (var i = 0; i < sel.ranges.length; i++) { - var range = sel.ranges[i]; - changes[i] = {from: range.from(), to: range.to(), text: this.splitLines(code[i]), origin: origin}; - } - var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse); - for (var i = changes.length - 1; i >= 0; i--) - makeChange(this, changes[i]); - if (newSel) setSelectionReplaceHistory(this, newSel); - else if (this.cm) ensureCursorVisible(this.cm); - }), - undo: docMethodOp(function() {makeChangeFromHistory(this, "undo");}), - redo: docMethodOp(function() {makeChangeFromHistory(this, "redo");}), - undoSelection: docMethodOp(function() {makeChangeFromHistory(this, "undo", true);}), - redoSelection: docMethodOp(function() {makeChangeFromHistory(this, "redo", true);}), - - setExtending: function(val) {this.extend = val;}, - getExtending: function() {return this.extend;}, - - historySize: function() { - var hist = this.history, done = 0, undone = 0; - for (var i = 0; i < hist.done.length; i++) if (!hist.done[i].ranges) ++done; - for (var i = 0; i < hist.undone.length; i++) if (!hist.undone[i].ranges) ++undone; - return {undo: done, redo: undone}; - }, - clearHistory: function() {this.history = new History(this.history.maxGeneration);}, - - markClean: function() { - this.cleanGeneration = this.changeGeneration(true); - }, - changeGeneration: function(forceSplit) { - if (forceSplit) - this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null; - return this.history.generation; - }, - isClean: function (gen) { - return this.history.generation == (gen || this.cleanGeneration); - }, - - getHistory: function() { - return {done: copyHistoryArray(this.history.done), - undone: copyHistoryArray(this.history.undone)}; - }, - setHistory: function(histData) { - var hist = this.history = new History(this.history.maxGeneration); - hist.done = copyHistoryArray(histData.done.slice(0), null, true); - hist.undone = copyHistoryArray(histData.undone.slice(0), null, true); - }, - - addLineClass: docMethodOp(function(handle, where, cls) { - return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function(line) { - var prop = where == "text" ? "textClass" - : where == "background" ? "bgClass" - : where == "gutter" ? "gutterClass" : "wrapClass"; - if (!line[prop]) line[prop] = cls; - else if (classTest(cls).test(line[prop])) return false; - else line[prop] += " " + cls; - return true; - }); - }), - removeLineClass: docMethodOp(function(handle, where, cls) { - return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function(line) { - var prop = where == "text" ? "textClass" - : where == "background" ? "bgClass" - : where == "gutter" ? "gutterClass" : "wrapClass"; - var cur = line[prop]; - if (!cur) return false; - else if (cls == null) line[prop] = null; - else { - var found = cur.match(classTest(cls)); - if (!found) return false; - var end = found.index + found[0].length; - line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null; - } - return true; - }); - }), - - addLineWidget: docMethodOp(function(handle, node, options) { - return addLineWidget(this, handle, node, options); - }), - removeLineWidget: function(widget) { widget.clear(); }, - - markText: function(from, to, options) { - return markText(this, clipPos(this, from), clipPos(this, to), options, options && options.type || "range"); - }, - setBookmark: function(pos, options) { - var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options), - insertLeft: options && options.insertLeft, - clearWhenEmpty: false, shared: options && options.shared, - handleMouseEvents: options && options.handleMouseEvents}; - pos = clipPos(this, pos); - return markText(this, pos, pos, realOpts, "bookmark"); - }, - findMarksAt: function(pos) { - pos = clipPos(this, pos); - var markers = [], spans = getLine(this, pos.line).markedSpans; - if (spans) for (var i = 0; i < spans.length; ++i) { - var span = spans[i]; - if ((span.from == null || span.from <= pos.ch) && - (span.to == null || span.to >= pos.ch)) - markers.push(span.marker.parent || span.marker); - } - return markers; - }, - findMarks: function(from, to, filter) { - from = clipPos(this, from); to = clipPos(this, to); - var found = [], lineNo = from.line; - this.iter(from.line, to.line + 1, function(line) { - var spans = line.markedSpans; - if (spans) for (var i = 0; i < spans.length; i++) { - var span = spans[i]; - if (!(lineNo == from.line && from.ch > span.to || - span.from == null && lineNo != from.line|| - lineNo == to.line && span.from > to.ch) && - (!filter || filter(span.marker))) - found.push(span.marker.parent || span.marker); - } - ++lineNo; - }); - return found; - }, - getAllMarks: function() { - var markers = []; - this.iter(function(line) { - var sps = line.markedSpans; - if (sps) for (var i = 0; i < sps.length; ++i) - if (sps[i].from != null) markers.push(sps[i].marker); - }); - return markers; - }, - - posFromIndex: function(off) { - var ch, lineNo = this.first; - this.iter(function(line) { - var sz = line.text.length + 1; - if (sz > off) { ch = off; return true; } - off -= sz; - ++lineNo; - }); - return clipPos(this, Pos(lineNo, ch)); - }, - indexFromPos: function (coords) { - coords = clipPos(this, coords); - var index = coords.ch; - if (coords.line < this.first || coords.ch < 0) return 0; - this.iter(this.first, coords.line, function (line) { - index += line.text.length + 1; - }); - return index; - }, - - copy: function(copyHistory) { - var doc = new Doc(getLines(this, this.first, this.first + this.size), - this.modeOption, this.first, this.lineSep); - doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft; - doc.sel = this.sel; - doc.extend = false; - if (copyHistory) { - doc.history.undoDepth = this.history.undoDepth; - doc.setHistory(this.getHistory()); - } - return doc; - }, - - linkedDoc: function(options) { - if (!options) options = {}; - var from = this.first, to = this.first + this.size; - if (options.from != null && options.from > from) from = options.from; - if (options.to != null && options.to < to) to = options.to; - var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from, this.lineSep); - if (options.sharedHist) copy.history = this.history; - (this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist}); - copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}]; - copySharedMarkers(copy, findSharedMarkers(this)); - return copy; - }, - unlinkDoc: function(other) { - if (other instanceof CodeMirror) other = other.doc; - if (this.linked) for (var i = 0; i < this.linked.length; ++i) { - var link = this.linked[i]; - if (link.doc != other) continue; - this.linked.splice(i, 1); - other.unlinkDoc(this); - detachSharedMarkers(findSharedMarkers(this)); - break; - } - // If the histories were shared, split them again - if (other.history == this.history) { - var splitIds = [other.id]; - linkedDocs(other, function(doc) {splitIds.push(doc.id);}, true); - other.history = new History(null); - other.history.done = copyHistoryArray(this.history.done, splitIds); - other.history.undone = copyHistoryArray(this.history.undone, splitIds); - } - }, - iterLinkedDocs: function(f) {linkedDocs(this, f);}, - - getMode: function() {return this.mode;}, - getEditor: function() {return this.cm;}, - - splitLines: function(str) { - if (this.lineSep) return str.split(this.lineSep); - return splitLinesAuto(str); - }, - lineSeparator: function() { return this.lineSep || "\n"; } - }); - - // Public alias. - Doc.prototype.eachLine = Doc.prototype.iter; - - // Set up methods on CodeMirror's prototype to redirect to the editor's document. - var dontDelegate = "iter insert remove copy getEditor constructor".split(" "); - for (var prop in Doc.prototype) if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0) - CodeMirror.prototype[prop] = (function(method) { - return function() {return method.apply(this.doc, arguments);}; - })(Doc.prototype[prop]); - - eventMixin(Doc); - - // Call f for all linked documents. - function linkedDocs(doc, f, sharedHistOnly) { - function propagate(doc, skip, sharedHist) { - if (doc.linked) for (var i = 0; i < doc.linked.length; ++i) { - var rel = doc.linked[i]; - if (rel.doc == skip) continue; - var shared = sharedHist && rel.sharedHist; - if (sharedHistOnly && !shared) continue; - f(rel.doc, shared); - propagate(rel.doc, doc, shared); - } - } - propagate(doc, null, true); - } - - // Attach a document to an editor. - function attachDoc(cm, doc) { - if (doc.cm) throw new Error("This document is already in use."); - cm.doc = doc; - doc.cm = cm; - estimateLineHeights(cm); - loadMode(cm); - if (!cm.options.lineWrapping) findMaxLine(cm); - cm.options.mode = doc.modeOption; - regChange(cm); - } - - // LINE UTILITIES - - // Find the line object corresponding to the given line number. - function getLine(doc, n) { - n -= doc.first; - if (n < 0 || n >= doc.size) throw new Error("There is no line " + (n + doc.first) + " in the document."); - for (var chunk = doc; !chunk.lines;) { - for (var i = 0;; ++i) { - var child = chunk.children[i], sz = child.chunkSize(); - if (n < sz) { chunk = child; break; } - n -= sz; - } - } - return chunk.lines[n]; - } - - // Get the part of a document between two positions, as an array of - // strings. - function getBetween(doc, start, end) { - var out = [], n = start.line; - doc.iter(start.line, end.line + 1, function(line) { - var text = line.text; - if (n == end.line) text = text.slice(0, end.ch); - if (n == start.line) text = text.slice(start.ch); - out.push(text); - ++n; - }); - return out; - } - // Get the lines between from and to, as array of strings. - function getLines(doc, from, to) { - var out = []; - doc.iter(from, to, function(line) { out.push(line.text); }); - return out; - } - - // Update the height of a line, propagating the height change - // upwards to parent nodes. - function updateLineHeight(line, height) { - var diff = height - line.height; - if (diff) for (var n = line; n; n = n.parent) n.height += diff; - } - - // Given a line object, find its line number by walking up through - // its parent links. - function lineNo(line) { - if (line.parent == null) return null; - var cur = line.parent, no = indexOf(cur.lines, line); - for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) { - for (var i = 0;; ++i) { - if (chunk.children[i] == cur) break; - no += chunk.children[i].chunkSize(); - } - } - return no + cur.first; - } - - // Find the line at the given vertical position, using the height - // information in the document tree. - function lineAtHeight(chunk, h) { - var n = chunk.first; - outer: do { - for (var i = 0; i < chunk.children.length; ++i) { - var child = chunk.children[i], ch = child.height; - if (h < ch) { chunk = child; continue outer; } - h -= ch; - n += child.chunkSize(); - } - return n; - } while (!chunk.lines); - for (var i = 0; i < chunk.lines.length; ++i) { - var line = chunk.lines[i], lh = line.height; - if (h < lh) break; - h -= lh; - } - return n + i; - } - - - // Find the height above the given line. - function heightAtLine(lineObj) { - lineObj = visualLine(lineObj); - - var h = 0, chunk = lineObj.parent; - for (var i = 0; i < chunk.lines.length; ++i) { - var line = chunk.lines[i]; - if (line == lineObj) break; - else h += line.height; - } - for (var p = chunk.parent; p; chunk = p, p = chunk.parent) { - for (var i = 0; i < p.children.length; ++i) { - var cur = p.children[i]; - if (cur == chunk) break; - else h += cur.height; - } - } - return h; - } - - // Get the bidi ordering for the given line (and cache it). Returns - // false for lines that are fully left-to-right, and an array of - // BidiSpan objects otherwise. - function getOrder(line) { - var order = line.order; - if (order == null) order = line.order = bidiOrdering(line.text); - return order; - } - - // HISTORY - - function History(startGen) { - // Arrays of change events and selections. Doing something adds an - // event to done and clears undo. Undoing moves events from done - // to undone, redoing moves them in the other direction. - this.done = []; this.undone = []; - this.undoDepth = Infinity; - // Used to track when changes can be merged into a single undo - // event - this.lastModTime = this.lastSelTime = 0; - this.lastOp = this.lastSelOp = null; - this.lastOrigin = this.lastSelOrigin = null; - // Used by the isClean() method - this.generation = this.maxGeneration = startGen || 1; - } - - // Create a history change event from an updateDoc-style change - // object. - function historyChangeFromChange(doc, change) { - var histChange = {from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to)}; - attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1); - linkedDocs(doc, function(doc) {attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);}, true); - return histChange; - } - - // Pop all selection events off the end of a history array. Stop at - // a change event. - function clearSelectionEvents(array) { - while (array.length) { - var last = lst(array); - if (last.ranges) array.pop(); - else break; - } - } - - // Find the top change event in the history. Pop off selection - // events that are in the way. - function lastChangeEvent(hist, force) { - if (force) { - clearSelectionEvents(hist.done); - return lst(hist.done); - } else if (hist.done.length && !lst(hist.done).ranges) { - return lst(hist.done); - } else if (hist.done.length > 1 && !hist.done[hist.done.length - 2].ranges) { - hist.done.pop(); - return lst(hist.done); - } - } - - // Register a change in the history. Merges changes that are within - // a single operation, ore are close together with an origin that - // allows merging (starting with "+") into a single event. - function addChangeToHistory(doc, change, selAfter, opId) { - var hist = doc.history; - hist.undone.length = 0; - var time = +new Date, cur; - - if ((hist.lastOp == opId || - hist.lastOrigin == change.origin && change.origin && - ((change.origin.charAt(0) == "+" && doc.cm && hist.lastModTime > time - doc.cm.options.historyEventDelay) || - change.origin.charAt(0) == "*")) && - (cur = lastChangeEvent(hist, hist.lastOp == opId))) { - // Merge this change into the last event - var last = lst(cur.changes); - if (cmp(change.from, change.to) == 0 && cmp(change.from, last.to) == 0) { - // Optimized case for simple insertion -- don't want to add - // new changesets for every character typed - last.to = changeEnd(change); - } else { - // Add new sub-event - cur.changes.push(historyChangeFromChange(doc, change)); - } - } else { - // Can not be merged, start a new event. - var before = lst(hist.done); - if (!before || !before.ranges) - pushSelectionToHistory(doc.sel, hist.done); - cur = {changes: [historyChangeFromChange(doc, change)], - generation: hist.generation}; - hist.done.push(cur); - while (hist.done.length > hist.undoDepth) { - hist.done.shift(); - if (!hist.done[0].ranges) hist.done.shift(); - } - } - hist.done.push(selAfter); - hist.generation = ++hist.maxGeneration; - hist.lastModTime = hist.lastSelTime = time; - hist.lastOp = hist.lastSelOp = opId; - hist.lastOrigin = hist.lastSelOrigin = change.origin; - - if (!last) signal(doc, "historyAdded"); - } - - function selectionEventCanBeMerged(doc, origin, prev, sel) { - var ch = origin.charAt(0); - return ch == "*" || - ch == "+" && - prev.ranges.length == sel.ranges.length && - prev.somethingSelected() == sel.somethingSelected() && - new Date - doc.history.lastSelTime <= (doc.cm ? doc.cm.options.historyEventDelay : 500); - } - - // Called whenever the selection changes, sets the new selection as - // the pending selection in the history, and pushes the old pending - // selection into the 'done' array when it was significantly - // different (in number of selected ranges, emptiness, or time). - function addSelectionToHistory(doc, sel, opId, options) { - var hist = doc.history, origin = options && options.origin; - - // A new event is started when the previous origin does not match - // the current, or the origins don't allow matching. Origins - // starting with * are always merged, those starting with + are - // merged when similar and close together in time. - if (opId == hist.lastSelOp || - (origin && hist.lastSelOrigin == origin && - (hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin || - selectionEventCanBeMerged(doc, origin, lst(hist.done), sel)))) - hist.done[hist.done.length - 1] = sel; - else - pushSelectionToHistory(sel, hist.done); - - hist.lastSelTime = +new Date; - hist.lastSelOrigin = origin; - hist.lastSelOp = opId; - if (options && options.clearRedo !== false) - clearSelectionEvents(hist.undone); - } - - function pushSelectionToHistory(sel, dest) { - var top = lst(dest); - if (!(top && top.ranges && top.equals(sel))) - dest.push(sel); - } - - // Used to store marked span information in the history. - function attachLocalSpans(doc, change, from, to) { - var existing = change["spans_" + doc.id], n = 0; - doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function(line) { - if (line.markedSpans) - (existing || (existing = change["spans_" + doc.id] = {}))[n] = line.markedSpans; - ++n; - }); - } - - // When un/re-doing restores text containing marked spans, those - // that have been explicitly cleared should not be restored. - function removeClearedSpans(spans) { - if (!spans) return null; - for (var i = 0, out; i < spans.length; ++i) { - if (spans[i].marker.explicitlyCleared) { if (!out) out = spans.slice(0, i); } - else if (out) out.push(spans[i]); - } - return !out ? spans : out.length ? out : null; - } - - // Retrieve and filter the old marked spans stored in a change event. - function getOldSpans(doc, change) { - var found = change["spans_" + doc.id]; - if (!found) return null; - for (var i = 0, nw = []; i < change.text.length; ++i) - nw.push(removeClearedSpans(found[i])); - return nw; - } - - // Used both to provide a JSON-safe object in .getHistory, and, when - // detaching a document, to split the history in two - function copyHistoryArray(events, newGroup, instantiateSel) { - for (var i = 0, copy = []; i < events.length; ++i) { - var event = events[i]; - if (event.ranges) { - copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event); - continue; - } - var changes = event.changes, newChanges = []; - copy.push({changes: newChanges}); - for (var j = 0; j < changes.length; ++j) { - var change = changes[j], m; - newChanges.push({from: change.from, to: change.to, text: change.text}); - if (newGroup) for (var prop in change) if (m = prop.match(/^spans_(\d+)$/)) { - if (indexOf(newGroup, Number(m[1])) > -1) { - lst(newChanges)[prop] = change[prop]; - delete change[prop]; - } - } - } - } - return copy; - } - - // Rebasing/resetting history to deal with externally-sourced changes - - function rebaseHistSelSingle(pos, from, to, diff) { - if (to < pos.line) { - pos.line += diff; - } else if (from < pos.line) { - pos.line = from; - pos.ch = 0; - } - } - - // Tries to rebase an array of history events given a change in the - // document. If the change touches the same lines as the event, the - // event, and everything 'behind' it, is discarded. If the change is - // before the event, the event's positions are updated. Uses a - // copy-on-write scheme for the positions, to avoid having to - // reallocate them all on every rebase, but also avoid problems with - // shared position objects being unsafely updated. - function rebaseHistArray(array, from, to, diff) { - for (var i = 0; i < array.length; ++i) { - var sub = array[i], ok = true; - if (sub.ranges) { - if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true; } - for (var j = 0; j < sub.ranges.length; j++) { - rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff); - rebaseHistSelSingle(sub.ranges[j].head, from, to, diff); - } - continue; - } - for (var j = 0; j < sub.changes.length; ++j) { - var cur = sub.changes[j]; - if (to < cur.from.line) { - cur.from = Pos(cur.from.line + diff, cur.from.ch); - cur.to = Pos(cur.to.line + diff, cur.to.ch); - } else if (from <= cur.to.line) { - ok = false; - break; - } - } - if (!ok) { - array.splice(0, i + 1); - i = 0; - } - } - } - - function rebaseHist(hist, change) { - var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1; - rebaseHistArray(hist.done, from, to, diff); - rebaseHistArray(hist.undone, from, to, diff); - } - - // EVENT UTILITIES - - // Due to the fact that we still support jurassic IE versions, some - // compatibility wrappers are needed. - - var e_preventDefault = CodeMirror.e_preventDefault = function(e) { - if (e.preventDefault) e.preventDefault(); - else e.returnValue = false; - }; - var e_stopPropagation = CodeMirror.e_stopPropagation = function(e) { - if (e.stopPropagation) e.stopPropagation(); - else e.cancelBubble = true; - }; - function e_defaultPrevented(e) { - return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false; - } - var e_stop = CodeMirror.e_stop = function(e) {e_preventDefault(e); e_stopPropagation(e);}; - - function e_target(e) {return e.target || e.srcElement;} - function e_button(e) { - var b = e.which; - if (b == null) { - if (e.button & 1) b = 1; - else if (e.button & 2) b = 3; - else if (e.button & 4) b = 2; - } - if (mac && e.ctrlKey && b == 1) b = 3; - return b; - } - - // EVENT HANDLING - - // Lightweight event framework. on/off also work on DOM nodes, - // registering native DOM handlers. - - var on = CodeMirror.on = function(emitter, type, f) { - if (emitter.addEventListener) - emitter.addEventListener(type, f, false); - else if (emitter.attachEvent) - emitter.attachEvent("on" + type, f); - else { - var map = emitter._handlers || (emitter._handlers = {}); - var arr = map[type] || (map[type] = []); - arr.push(f); - } - }; - - var noHandlers = [] - function getHandlers(emitter, type, copy) { - var arr = emitter._handlers && emitter._handlers[type] - if (copy) return arr && arr.length > 0 ? arr.slice() : noHandlers - else return arr || noHandlers - } - - var off = CodeMirror.off = function(emitter, type, f) { - if (emitter.removeEventListener) - emitter.removeEventListener(type, f, false); - else if (emitter.detachEvent) - emitter.detachEvent("on" + type, f); - else { - var handlers = getHandlers(emitter, type, false) - for (var i = 0; i < handlers.length; ++i) - if (handlers[i] == f) { handlers.splice(i, 1); break; } - } - }; - - var signal = CodeMirror.signal = function(emitter, type /*, values...*/) { - var handlers = getHandlers(emitter, type, true) - if (!handlers.length) return; - var args = Array.prototype.slice.call(arguments, 2); - for (var i = 0; i < handlers.length; ++i) handlers[i].apply(null, args); - }; - - var orphanDelayedCallbacks = null; - - // Often, we want to signal events at a point where we are in the - // middle of some work, but don't want the handler to start calling - // other methods on the editor, which might be in an inconsistent - // state or simply not expect any other events to happen. - // signalLater looks whether there are any handlers, and schedules - // them to be executed when the last operation ends, or, if no - // operation is active, when a timeout fires. - function signalLater(emitter, type /*, values...*/) { - var arr = getHandlers(emitter, type, false) - if (!arr.length) return; - var args = Array.prototype.slice.call(arguments, 2), list; - if (operationGroup) { - list = operationGroup.delayedCallbacks; - } else if (orphanDelayedCallbacks) { - list = orphanDelayedCallbacks; - } else { - list = orphanDelayedCallbacks = []; - setTimeout(fireOrphanDelayed, 0); - } - function bnd(f) {return function(){f.apply(null, args);};}; - for (var i = 0; i < arr.length; ++i) - list.push(bnd(arr[i])); - } - - function fireOrphanDelayed() { - var delayed = orphanDelayedCallbacks; - orphanDelayedCallbacks = null; - for (var i = 0; i < delayed.length; ++i) delayed[i](); - } - - // The DOM events that CodeMirror handles can be overridden by - // registering a (non-DOM) handler on the editor for the event name, - // and preventDefault-ing the event in that handler. - function signalDOMEvent(cm, e, override) { - if (typeof e == "string") - e = {type: e, preventDefault: function() { this.defaultPrevented = true; }}; - signal(cm, override || e.type, cm, e); - return e_defaultPrevented(e) || e.codemirrorIgnore; - } - - function signalCursorActivity(cm) { - var arr = cm._handlers && cm._handlers.cursorActivity; - if (!arr) return; - var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []); - for (var i = 0; i < arr.length; ++i) if (indexOf(set, arr[i]) == -1) - set.push(arr[i]); - } - - function hasHandler(emitter, type) { - return getHandlers(emitter, type).length > 0 - } - - // Add on and off methods to a constructor's prototype, to make - // registering events on such objects more convenient. - function eventMixin(ctor) { - ctor.prototype.on = function(type, f) {on(this, type, f);}; - ctor.prototype.off = function(type, f) {off(this, type, f);}; - } - - // MISC UTILITIES - - // Number of pixels added to scroller and sizer to hide scrollbar - var scrollerGap = 30; - - // Returned or thrown by various protocols to signal 'I'm not - // handling this'. - var Pass = CodeMirror.Pass = {toString: function(){return "CodeMirror.Pass";}}; - - // Reused option objects for setSelection & friends - var sel_dontScroll = {scroll: false}, sel_mouse = {origin: "*mouse"}, sel_move = {origin: "+move"}; - - function Delayed() {this.id = null;} - Delayed.prototype.set = function(ms, f) { - clearTimeout(this.id); - this.id = setTimeout(f, ms); - }; - - // Counts the column offset in a string, taking tabs into account. - // Used mostly to find indentation. - var countColumn = CodeMirror.countColumn = function(string, end, tabSize, startIndex, startValue) { - if (end == null) { - end = string.search(/[^\s\u00a0]/); - if (end == -1) end = string.length; - } - for (var i = startIndex || 0, n = startValue || 0;;) { - var nextTab = string.indexOf("\t", i); - if (nextTab < 0 || nextTab >= end) - return n + (end - i); - n += nextTab - i; - n += tabSize - (n % tabSize); - i = nextTab + 1; - } - }; - - // The inverse of countColumn -- find the offset that corresponds to - // a particular column. - var findColumn = CodeMirror.findColumn = function(string, goal, tabSize) { - for (var pos = 0, col = 0;;) { - var nextTab = string.indexOf("\t", pos); - if (nextTab == -1) nextTab = string.length; - var skipped = nextTab - pos; - if (nextTab == string.length || col + skipped >= goal) - return pos + Math.min(skipped, goal - col); - col += nextTab - pos; - col += tabSize - (col % tabSize); - pos = nextTab + 1; - if (col >= goal) return pos; - } - } - - var spaceStrs = [""]; - function spaceStr(n) { - while (spaceStrs.length <= n) - spaceStrs.push(lst(spaceStrs) + " "); - return spaceStrs[n]; - } - - function lst(arr) { return arr[arr.length-1]; } - - var selectInput = function(node) { node.select(); }; - if (ios) // Mobile Safari apparently has a bug where select() is broken. - selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length; }; - else if (ie) // Suppress mysterious IE10 errors - selectInput = function(node) { try { node.select(); } catch(_e) {} }; - - function indexOf(array, elt) { - for (var i = 0; i < array.length; ++i) - if (array[i] == elt) return i; - return -1; - } - function map(array, f) { - var out = []; - for (var i = 0; i < array.length; i++) out[i] = f(array[i], i); - return out; - } - - function nothing() {} - - function createObj(base, props) { - var inst; - if (Object.create) { - inst = Object.create(base); - } else { - nothing.prototype = base; - inst = new nothing(); - } - if (props) copyObj(props, inst); - return inst; - }; - - function copyObj(obj, target, overwrite) { - if (!target) target = {}; - for (var prop in obj) - if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop))) - target[prop] = obj[prop]; - return target; - } - - function bind(f) { - var args = Array.prototype.slice.call(arguments, 1); - return function(){return f.apply(null, args);}; - } - - var nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/; - var isWordCharBasic = CodeMirror.isWordChar = function(ch) { - return /\w/.test(ch) || ch > "\x80" && - (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch)); - }; - function isWordChar(ch, helper) { - if (!helper) return isWordCharBasic(ch); - if (helper.source.indexOf("\\w") > -1 && isWordCharBasic(ch)) return true; - return helper.test(ch); - } - - function isEmpty(obj) { - for (var n in obj) if (obj.hasOwnProperty(n) && obj[n]) return false; - return true; - } - - // Extending unicode characters. A series of a non-extending char + - // any number of extending chars is treated as a single unit as far - // as editing and measuring is concerned. This is not fully correct, - // since some scripts/fonts/browsers also treat other configurations - // of code points as a group. - var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/; - function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch); } - - // DOM UTILITIES - - function elt(tag, content, className, style) { - var e = document.createElement(tag); - if (className) e.className = className; - if (style) e.style.cssText = style; - if (typeof content == "string") e.appendChild(document.createTextNode(content)); - else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]); - return e; - } - - var range; - if (document.createRange) range = function(node, start, end, endNode) { - var r = document.createRange(); - r.setEnd(endNode || node, end); - r.setStart(node, start); - return r; - }; - else range = function(node, start, end) { - var r = document.body.createTextRange(); - try { r.moveToElementText(node.parentNode); } - catch(e) { return r; } - r.collapse(true); - r.moveEnd("character", end); - r.moveStart("character", start); - return r; - }; - - function removeChildren(e) { - for (var count = e.childNodes.length; count > 0; --count) - e.removeChild(e.firstChild); - return e; - } - - function removeChildrenAndAdd(parent, e) { - return removeChildren(parent).appendChild(e); - } - - var contains = CodeMirror.contains = function(parent, child) { - if (child.nodeType == 3) // Android browser always returns false when child is a textnode - child = child.parentNode; - if (parent.contains) - return parent.contains(child); - do { - if (child.nodeType == 11) child = child.host; - if (child == parent) return true; - } while (child = child.parentNode); - }; - - function activeElt() { - var activeElement = document.activeElement; - while (activeElement && activeElement.root && activeElement.root.activeElement) - activeElement = activeElement.root.activeElement; - return activeElement; - } - // Older versions of IE throws unspecified error when touching - // document.activeElement in some cases (during loading, in iframe) - if (ie && ie_version < 11) activeElt = function() { - try { return document.activeElement; } - catch(e) { return document.body; } - }; - - function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*"); } - var rmClass = CodeMirror.rmClass = function(node, cls) { - var current = node.className; - var match = classTest(cls).exec(current); - if (match) { - var after = current.slice(match.index + match[0].length); - node.className = current.slice(0, match.index) + (after ? match[1] + after : ""); - } - }; - var addClass = CodeMirror.addClass = function(node, cls) { - var current = node.className; - if (!classTest(cls).test(current)) node.className += (current ? " " : "") + cls; - }; - function joinClasses(a, b) { - var as = a.split(" "); - for (var i = 0; i < as.length; i++) - if (as[i] && !classTest(as[i]).test(b)) b += " " + as[i]; - return b; - } - - // WINDOW-WIDE EVENTS - - // These must be handled carefully, because naively registering a - // handler for each editor will cause the editors to never be - // garbage collected. - - function forEachCodeMirror(f) { - if (!document.body.getElementsByClassName) return; - var byClass = document.body.getElementsByClassName("CodeMirror"); - for (var i = 0; i < byClass.length; i++) { - var cm = byClass[i].CodeMirror; - if (cm) f(cm); - } - } - - var globalsRegistered = false; - function ensureGlobalHandlers() { - if (globalsRegistered) return; - registerGlobalHandlers(); - globalsRegistered = true; - } - function registerGlobalHandlers() { - // When the window resizes, we need to refresh active editors. - var resizeTimer; - on(window, "resize", function() { - if (resizeTimer == null) resizeTimer = setTimeout(function() { - resizeTimer = null; - forEachCodeMirror(onResize); - }, 100); - }); - // When the window loses focus, we want to show the editor as blurred - on(window, "blur", function() { - forEachCodeMirror(onBlur); - }); - } - - // FEATURE DETECTION - - // Detect drag-and-drop - var dragAndDrop = function() { - // There is *some* kind of drag-and-drop support in IE6-8, but I - // couldn't get it to work yet. - if (ie && ie_version < 9) return false; - var div = elt('div'); - return "draggable" in div || "dragDrop" in div; - }(); - - var zwspSupported; - function zeroWidthElement(measure) { - if (zwspSupported == null) { - var test = elt("span", "\u200b"); - removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")])); - if (measure.firstChild.offsetHeight != 0) - zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8); - } - var node = zwspSupported ? elt("span", "\u200b") : - elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px"); - node.setAttribute("cm-text", ""); - return node; - } - - // Feature-detect IE's crummy client rect reporting for bidi text - var badBidiRects; - function hasBadBidiRects(measure) { - if (badBidiRects != null) return badBidiRects; - var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA")); - var r0 = range(txt, 0, 1).getBoundingClientRect(); - if (!r0 || r0.left == r0.right) return false; // Safari returns null in some cases (#2780) - var r1 = range(txt, 1, 2).getBoundingClientRect(); - return badBidiRects = (r1.right - r0.right < 3); - } - - // See if "".split is the broken IE version, if so, provide an - // alternative way to split lines. - var splitLinesAuto = CodeMirror.splitLines = "\n\nb".split(/\n/).length != 3 ? function(string) { - var pos = 0, result = [], l = string.length; - while (pos <= l) { - var nl = string.indexOf("\n", pos); - if (nl == -1) nl = string.length; - var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl); - var rt = line.indexOf("\r"); - if (rt != -1) { - result.push(line.slice(0, rt)); - pos += rt + 1; - } else { - result.push(line); - pos = nl + 1; - } - } - return result; - } : function(string){return string.split(/\r\n?|\n/);}; - - var hasSelection = window.getSelection ? function(te) { - try { return te.selectionStart != te.selectionEnd; } - catch(e) { return false; } - } : function(te) { - try {var range = te.ownerDocument.selection.createRange();} - catch(e) {} - if (!range || range.parentElement() != te) return false; - return range.compareEndPoints("StartToEnd", range) != 0; - }; - - var hasCopyEvent = (function() { - var e = elt("div"); - if ("oncopy" in e) return true; - e.setAttribute("oncopy", "return;"); - return typeof e.oncopy == "function"; - })(); - - var badZoomedRects = null; - function hasBadZoomedRects(measure) { - if (badZoomedRects != null) return badZoomedRects; - var node = removeChildrenAndAdd(measure, elt("span", "x")); - var normal = node.getBoundingClientRect(); - var fromRange = range(node, 0, 1).getBoundingClientRect(); - return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1; - } - - // KEY NAMES - - var keyNames = CodeMirror.keyNames = { - 3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt", - 19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End", - 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert", - 46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod", - 106: "*", 107: "=", 109: "-", 110: ".", 111: "/", 127: "Delete", - 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\", - 221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete", - 63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert" - }; - (function() { - // Number keys - for (var i = 0; i < 10; i++) keyNames[i + 48] = keyNames[i + 96] = String(i); - // Alphabetic keys - for (var i = 65; i <= 90; i++) keyNames[i] = String.fromCharCode(i); - // Function keys - for (var i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = "F" + i; - })(); - - // BIDI HELPERS - - function iterateBidiSections(order, from, to, f) { - if (!order) return f(from, to, "ltr"); - var found = false; - for (var i = 0; i < order.length; ++i) { - var part = order[i]; - if (part.from < to && part.to > from || from == to && part.to == from) { - f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr"); - found = true; - } - } - if (!found) f(from, to, "ltr"); - } - - function bidiLeft(part) { return part.level % 2 ? part.to : part.from; } - function bidiRight(part) { return part.level % 2 ? part.from : part.to; } - - function lineLeft(line) { var order = getOrder(line); return order ? bidiLeft(order[0]) : 0; } - function lineRight(line) { - var order = getOrder(line); - if (!order) return line.text.length; - return bidiRight(lst(order)); - } - - function lineStart(cm, lineN) { - var line = getLine(cm.doc, lineN); - var visual = visualLine(line); - if (visual != line) lineN = lineNo(visual); - var order = getOrder(visual); - var ch = !order ? 0 : order[0].level % 2 ? lineRight(visual) : lineLeft(visual); - return Pos(lineN, ch); - } - function lineEnd(cm, lineN) { - var merged, line = getLine(cm.doc, lineN); - while (merged = collapsedSpanAtEnd(line)) { - line = merged.find(1, true).line; - lineN = null; - } - var order = getOrder(line); - var ch = !order ? line.text.length : order[0].level % 2 ? lineLeft(line) : lineRight(line); - return Pos(lineN == null ? lineNo(line) : lineN, ch); - } - function lineStartSmart(cm, pos) { - var start = lineStart(cm, pos.line); - var line = getLine(cm.doc, start.line); - var order = getOrder(line); - if (!order || order[0].level == 0) { - var firstNonWS = Math.max(0, line.text.search(/\S/)); - var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch; - return Pos(start.line, inWS ? 0 : firstNonWS); - } - return start; - } - - function compareBidiLevel(order, a, b) { - var linedir = order[0].level; - if (a == linedir) return true; - if (b == linedir) return false; - return a < b; - } - var bidiOther; - function getBidiPartAt(order, pos) { - bidiOther = null; - for (var i = 0, found; i < order.length; ++i) { - var cur = order[i]; - if (cur.from < pos && cur.to > pos) return i; - if ((cur.from == pos || cur.to == pos)) { - if (found == null) { - found = i; - } else if (compareBidiLevel(order, cur.level, order[found].level)) { - if (cur.from != cur.to) bidiOther = found; - return i; - } else { - if (cur.from != cur.to) bidiOther = i; - return found; - } - } - } - return found; - } - - function moveInLine(line, pos, dir, byUnit) { - if (!byUnit) return pos + dir; - do pos += dir; - while (pos > 0 && isExtendingChar(line.text.charAt(pos))); - return pos; - } - - // This is needed in order to move 'visually' through bi-directional - // text -- i.e., pressing left should make the cursor go left, even - // when in RTL text. The tricky part is the 'jumps', where RTL and - // LTR text touch each other. This often requires the cursor offset - // to move more than one unit, in order to visually move one unit. - function moveVisually(line, start, dir, byUnit) { - var bidi = getOrder(line); - if (!bidi) return moveLogically(line, start, dir, byUnit); - var pos = getBidiPartAt(bidi, start), part = bidi[pos]; - var target = moveInLine(line, start, part.level % 2 ? -dir : dir, byUnit); - - for (;;) { - if (target > part.from && target < part.to) return target; - if (target == part.from || target == part.to) { - if (getBidiPartAt(bidi, target) == pos) return target; - part = bidi[pos += dir]; - return (dir > 0) == part.level % 2 ? part.to : part.from; - } else { - part = bidi[pos += dir]; - if (!part) return null; - if ((dir > 0) == part.level % 2) - target = moveInLine(line, part.to, -1, byUnit); - else - target = moveInLine(line, part.from, 1, byUnit); - } - } - } - - function moveLogically(line, start, dir, byUnit) { - var target = start + dir; - if (byUnit) while (target > 0 && isExtendingChar(line.text.charAt(target))) target += dir; - return target < 0 || target > line.text.length ? null : target; - } - - // Bidirectional ordering algorithm - // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm - // that this (partially) implements. - - // One-char codes used for character types: - // L (L): Left-to-Right - // R (R): Right-to-Left - // r (AL): Right-to-Left Arabic - // 1 (EN): European Number - // + (ES): European Number Separator - // % (ET): European Number Terminator - // n (AN): Arabic Number - // , (CS): Common Number Separator - // m (NSM): Non-Spacing Mark - // b (BN): Boundary Neutral - // s (B): Paragraph Separator - // t (S): Segment Separator - // w (WS): Whitespace - // N (ON): Other Neutrals - - // Returns null if characters are ordered as they appear - // (left-to-right), or an array of sections ({from, to, level} - // objects) in the order in which they occur visually. - var bidiOrdering = (function() { - // Character types for codepoints 0 to 0xff - var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN"; - // Character types for codepoints 0x600 to 0x6ff - var arabicTypes = "rrrrrrrrrrrr,rNNmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmrrrrrrrnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmNmmmm"; - function charType(code) { - if (code <= 0xf7) return lowTypes.charAt(code); - else if (0x590 <= code && code <= 0x5f4) return "R"; - else if (0x600 <= code && code <= 0x6ed) return arabicTypes.charAt(code - 0x600); - else if (0x6ee <= code && code <= 0x8ac) return "r"; - else if (0x2000 <= code && code <= 0x200b) return "w"; - else if (code == 0x200c) return "b"; - else return "L"; - } - - var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/; - var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/; - // Browsers seem to always treat the boundaries of block elements as being L. - var outerType = "L"; - - function BidiSpan(level, from, to) { - this.level = level; - this.from = from; this.to = to; - } - - return function(str) { - if (!bidiRE.test(str)) return false; - var len = str.length, types = []; - for (var i = 0, type; i < len; ++i) - types.push(type = charType(str.charCodeAt(i))); - - // W1. Examine each non-spacing mark (NSM) in the level run, and - // change the type of the NSM to the type of the previous - // character. If the NSM is at the start of the level run, it will - // get the type of sor. - for (var i = 0, prev = outerType; i < len; ++i) { - var type = types[i]; - if (type == "m") types[i] = prev; - else prev = type; - } - - // W2. Search backwards from each instance of a European number - // until the first strong type (R, L, AL, or sor) is found. If an - // AL is found, change the type of the European number to Arabic - // number. - // W3. Change all ALs to R. - for (var i = 0, cur = outerType; i < len; ++i) { - var type = types[i]; - if (type == "1" && cur == "r") types[i] = "n"; - else if (isStrong.test(type)) { cur = type; if (type == "r") types[i] = "R"; } - } - - // W4. A single European separator between two European numbers - // changes to a European number. A single common separator between - // two numbers of the same type changes to that type. - for (var i = 1, prev = types[0]; i < len - 1; ++i) { - var type = types[i]; - if (type == "+" && prev == "1" && types[i+1] == "1") types[i] = "1"; - else if (type == "," && prev == types[i+1] && - (prev == "1" || prev == "n")) types[i] = prev; - prev = type; - } - - // W5. A sequence of European terminators adjacent to European - // numbers changes to all European numbers. - // W6. Otherwise, separators and terminators change to Other - // Neutral. - for (var i = 0; i < len; ++i) { - var type = types[i]; - if (type == ",") types[i] = "N"; - else if (type == "%") { - for (var end = i + 1; end < len && types[end] == "%"; ++end) {} - var replace = (i && types[i-1] == "!") || (end < len && types[end] == "1") ? "1" : "N"; - for (var j = i; j < end; ++j) types[j] = replace; - i = end - 1; - } - } - - // W7. Search backwards from each instance of a European number - // until the first strong type (R, L, or sor) is found. If an L is - // found, then change the type of the European number to L. - for (var i = 0, cur = outerType; i < len; ++i) { - var type = types[i]; - if (cur == "L" && type == "1") types[i] = "L"; - else if (isStrong.test(type)) cur = type; - } - - // N1. A sequence of neutrals takes the direction of the - // surrounding strong text if the text on both sides has the same - // direction. European and Arabic numbers act as if they were R in - // terms of their influence on neutrals. Start-of-level-run (sor) - // and end-of-level-run (eor) are used at level run boundaries. - // N2. Any remaining neutrals take the embedding direction. - for (var i = 0; i < len; ++i) { - if (isNeutral.test(types[i])) { - for (var end = i + 1; end < len && isNeutral.test(types[end]); ++end) {} - var before = (i ? types[i-1] : outerType) == "L"; - var after = (end < len ? types[end] : outerType) == "L"; - var replace = before || after ? "L" : "R"; - for (var j = i; j < end; ++j) types[j] = replace; - i = end - 1; - } - } - - // Here we depart from the documented algorithm, in order to avoid - // building up an actual levels array. Since there are only three - // levels (0, 1, 2) in an implementation that doesn't take - // explicit embedding into account, we can build up the order on - // the fly, without following the level-based algorithm. - var order = [], m; - for (var i = 0; i < len;) { - if (countsAsLeft.test(types[i])) { - var start = i; - for (++i; i < len && countsAsLeft.test(types[i]); ++i) {} - order.push(new BidiSpan(0, start, i)); - } else { - var pos = i, at = order.length; - for (++i; i < len && types[i] != "L"; ++i) {} - for (var j = pos; j < i;) { - if (countsAsNum.test(types[j])) { - if (pos < j) order.splice(at, 0, new BidiSpan(1, pos, j)); - var nstart = j; - for (++j; j < i && countsAsNum.test(types[j]); ++j) {} - order.splice(at, 0, new BidiSpan(2, nstart, j)); - pos = j; - } else ++j; - } - if (pos < i) order.splice(at, 0, new BidiSpan(1, pos, i)); - } - } - if (order[0].level == 1 && (m = str.match(/^\s+/))) { - order[0].from = m[0].length; - order.unshift(new BidiSpan(0, 0, m[0].length)); - } - if (lst(order).level == 1 && (m = str.match(/\s+$/))) { - lst(order).to -= m[0].length; - order.push(new BidiSpan(0, len - m[0].length, len)); - } - if (order[0].level == 2) - order.unshift(new BidiSpan(1, order[0].to, order[0].to)); - if (order[0].level != lst(order).level) - order.push(new BidiSpan(order[0].level, len, len)); - - return order; - }; - })(); - - // THE END - - CodeMirror.version = "5.12.0"; - - return CodeMirror; -}); diff --git a/src/demo/static/cypher/cypher.js b/src/demo/static/cypher/cypher.js deleted file mode 100644 index 107e4f6d2..000000000 --- a/src/demo/static/cypher/cypher.js +++ /dev/null @@ -1,146 +0,0 @@ -// CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: http://codemirror.net/LICENSE - -// By the Neo4j Team and contributors. -// https://github.com/neo4j-contrib/CodeMirror - -(function(mod) { - if (typeof exports == "object" && typeof module == "object") // CommonJS - mod(require("../../lib/codemirror")); - else if (typeof define == "function" && define.amd) // AMD - define(["../../lib/codemirror"], mod); - else // Plain browser env - mod(CodeMirror); -})(function(CodeMirror) { - "use strict"; - var wordRegexp = function(words) { - return new RegExp("^(?:" + words.join("|") + ")$", "i"); - }; - - CodeMirror.defineMode("cypher", function(config) { - var tokenBase = function(stream/*, state*/) { - var ch = stream.next(); - if (ch === "\"" || ch === "'") { - stream.match(/.+?["']/); - return "string"; - } - if (/[{}\(\),\.;\[\]]/.test(ch)) { - curPunc = ch; - return "node"; - } else if (ch === "/" && stream.eat("/")) { - stream.skipToEnd(); - return "comment"; - } else if (operatorChars.test(ch)) { - stream.eatWhile(operatorChars); - return null; - } else { - stream.eatWhile(/[_\w\d]/); - if (stream.eat(":")) { - stream.eatWhile(/[\w\d_\-]/); - return "atom"; - } - var word = stream.current(); - if (funcs.test(word)) return "builtin"; - if (preds.test(word)) return "def"; - if (keywords.test(word)) return "keyword"; - return "variable"; - } - }; - var pushContext = function(state, type, col) { - return state.context = { - prev: state.context, - indent: state.indent, - col: col, - type: type - }; - }; - var popContext = function(state) { - state.indent = state.context.indent; - return state.context = state.context.prev; - }; - var indentUnit = config.indentUnit; - var curPunc; - var funcs = wordRegexp(["abs", "acos", "allShortestPaths", "asin", "atan", "atan2", "avg", "ceil", "coalesce", "collect", "cos", "cot", "count", "degrees", "e", "endnode", "exp", "extract", "filter", "floor", "haversin", "head", "id", "keys", "labels", "last", "left", "length", "log", "log10", "lower", "ltrim", "max", "min", "node", "nodes", "percentileCont", "percentileDisc", "pi", "radians", "rand", "range", "reduce", "rel", "relationship", "relationships", "replace", "reverse", "right", "round", "rtrim", "shortestPath", "sign", "sin", "size", "split", "sqrt", "startnode", "stdev", "stdevp", "str", "substring", "sum", "tail", "tan", "timestamp", "toFloat", "toInt", "toString", "trim", "type", "upper"]); - var preds = wordRegexp(["all", "and", "any", "contains", "exists", "has", "in", "none", "not", "or", "single", "xor"]); - var keywords = wordRegexp(["as", "asc", "ascending", "assert", "by", "case", "commit", "constraint", "create", "csv", "cypher", "delete", "desc", "descending", "detach", "distinct", "drop", "else", "end", "ends", "explain", "false", "fieldterminator", "foreach", "from", "headers", "in", "index", "is", "join", "limit", "load", "match", "merge", "null", "on", "optional", "order", "periodic", "profile", "remove", "return", "scan", "set", "skip", "start", "starts", "then", "true", "union", "unique", "unwind", "using", "when", "where", "with"]); - var operatorChars = /[*+\-<>=&|~%^]/; - - return { - startState: function(/*base*/) { - return { - tokenize: tokenBase, - context: null, - indent: 0, - col: 0 - }; - }, - token: function(stream, state) { - if (stream.sol()) { - if (state.context && (state.context.align == null)) { - state.context.align = false; - } - state.indent = stream.indentation(); - } - if (stream.eatSpace()) { - return null; - } - var style = state.tokenize(stream, state); - if (style !== "comment" && state.context && (state.context.align == null) && state.context.type !== "pattern") { - state.context.align = true; - } - if (curPunc === "(") { - pushContext(state, ")", stream.column()); - } else if (curPunc === "[") { - pushContext(state, "]", stream.column()); - } else if (curPunc === "{") { - pushContext(state, "}", stream.column()); - } else if (/[\]\}\)]/.test(curPunc)) { - while (state.context && state.context.type === "pattern") { - popContext(state); - } - if (state.context && curPunc === state.context.type) { - popContext(state); - } - } else if (curPunc === "." && state.context && state.context.type === "pattern") { - popContext(state); - } else if (/atom|string|variable/.test(style) && state.context) { - if (/[\}\]]/.test(state.context.type)) { - pushContext(state, "pattern", stream.column()); - } else if (state.context.type === "pattern" && !state.context.align) { - state.context.align = true; - state.context.col = stream.column(); - } - } - return style; - }, - indent: function(state, textAfter) { - var firstChar = textAfter && textAfter.charAt(0); - var context = state.context; - if (/[\]\}]/.test(firstChar)) { - while (context && context.type === "pattern") { - context = context.prev; - } - } - var closing = context && firstChar === context.type; - if (!context) return 0; - if (context.type === "keywords") return CodeMirror.commands.newlineAndIndent; - if (context.align) return context.col + (closing ? 0 : 1); - return context.indent + (closing ? 0 : indentUnit); - } - }; - }); - - CodeMirror.modeExtensions["cypher"] = { - autoFormatLineBreaks: function(text) { - var i, lines, reProcessedPortion; - var lines = text.split("\n"); - var reProcessedPortion = /\s+\b(return|where|order by|match|with|skip|limit|create|delete|set)\b\s/g; - for (var i = 0; i < lines.length; i++) - lines[i] = lines[i].replace(reProcessedPortion, " \n$1 ").trim(); - return lines.join("\n"); - } - }; - - CodeMirror.defineMIME("application/x-cypher-query", "cypher"); - -}); diff --git a/src/demo/static/cypher/neo.css b/src/demo/static/cypher/neo.css deleted file mode 100644 index b28d5c65f..000000000 --- a/src/demo/static/cypher/neo.css +++ /dev/null @@ -1,43 +0,0 @@ -/* neo theme for codemirror */ - -/* Color scheme */ - -.cm-s-neo.CodeMirror { - background-color:#ffffff; - color:#2e383c; - line-height:1.4375; -} -.cm-s-neo .cm-comment { color:#75787b; } -.cm-s-neo .cm-keyword, .cm-s-neo .cm-property { color:#1d75b3; } -.cm-s-neo .cm-atom,.cm-s-neo .cm-number { color:#75438a; } -.cm-s-neo .cm-node,.cm-s-neo .cm-tag { color:#9c3328; } -.cm-s-neo .cm-string { color:#b35e14; } -.cm-s-neo .cm-variable,.cm-s-neo .cm-qualifier { color:#047d65; } - - -/* Editor styling */ - -.cm-s-neo pre { - padding:0; -} - -.cm-s-neo .CodeMirror-gutters { - border:none; - border-right:10px solid transparent; - background-color:transparent; -} - -.cm-s-neo .CodeMirror-linenumber { - padding:0; - color:#e0e2e5; -} - -.cm-s-neo .CodeMirror-guttermarker { color: #1d75b3; } -.cm-s-neo .CodeMirror-guttermarker-subtle { color: #e0e2e5; } - -.cm-s-neo .CodeMirror-cursor { - width: auto; - border: 0; - background: rgba(155,157,162,0.37); - z-index: 1; -} diff --git a/src/demo/static/demo.css b/src/demo/static/demo.css deleted file mode 100644 index 3171d97ba..000000000 --- a/src/demo/static/demo.css +++ /dev/null @@ -1,67 +0,0 @@ -body { - font-family: GillSans, Calibri, Trebuchet, sans-serif; - background-color: #eee; -} - -.CodeMirror pre { - font-size: 12px; -} - -/* label color inactive */ -.input-field label { - color: #000; -} - -/* label color active */ -.input-field input[type=text]:focus + label { - color: #007FFF; -} - -/* label bottom border color */ -.input-field input[type=text]:focus { - border-bottom: 1px solid #007FFF; - box-shadow: 0 1px 0 0 #007FFF; -} - -.input-field input[type=text] { - border-bottom: 1px solid #007FFF; - box-shadow: 0 1px 0 0 #007FFF; -} - -label#hostname_port { - font: normal 15px GillSans, Calibri, Trebuchet, sans-serif !important; -} - -#hostname_port { - font-size: 2; -} - -.w100 { - width: 100%; -} - -.title { - width: 80%; - color: #007FFF; -} - -.CodeMirror { - border-top: 1px solid #eee; - height: auto; -} - -svg, text { - font-size: 28; -} - -.btn { - background-color: #007FFF; -} - -.btn:hover { - background-color: #007FFF; -} - -.btn:focus { - background-color: #007FFF; -} diff --git a/src/demo/static/demo.html b/src/demo/static/demo.html deleted file mode 100644 index 7837e6a11..000000000 --- a/src/demo/static/demo.html +++ /dev/null @@ -1,198 +0,0 @@ -<!doctype html> -<html lang="en"> -<head> - <meta charset="utf-8"> - <title>Memgraph Demo</title> - - <link rel="stylesheet" href="demo.css"> - <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.5/css/materialize.min.css"> - <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> - <link rel="stylesheet" href="cypher/codemirror.css"> - <link rel="stylesheet" href="cypher/neo.css"> - - <link rel="stylesheet" href="https://cdn.rawgit.com/novus/nvd3/v1.8.1/build/nv.d3.css"> - <link rel="stylesheet" href="demo.css"> -</head> - -<body> - - <!-- title row --> - <div class="row"> - <div class="valign-wrapper"> - <div class="input-field col s2"> - <input value="localhost:7474" id="neo4j_url" type="text" class="validate"> - <label id="neo4j_url" for="neo4j_url">hostname:port</label> - </div> - <div class="col s2"> - <button id="run-neo4j" - class="btn waves-effect waves-light" - type="submit" name="action"> - Start Neo4j - </button> - </div> - <h1 class="valign center col s4">Graph Benchmark</h1> - <div class="col s2"> - <button id="run-memgraph" style="float:right;" - class="btn waves-effect waves-light right-align" - type="submit" name="action"> - Start Memgraph - </button> - </div> - <div class="input-field col s2"> - <input value="localhost:7475" id="memgraph_url" type="text" class="validate"> - <label id="memgraph_url" for="memgraph_url">hostname:port</label> - </div> - </div> - </div> - - <!-- neo4j cards --> - <div class="row"> - <div class="col s2"> - <div id="q-0-0" class="card"> - <div class="qps valign-wrapper"> - <div class="col s6"> - <h3 id="text" class="valign center w100">0</h3> - </div> - <div class="col s6"> - <canvas id="gauge" width="150" height="60" - class="valign center"></canvas> - </div> - </div> - <textarea id="query">MATCH (n:Person) RETURN n</textarea> - </div> - <div id="q-0-1" class="card"> - <div class="qps valign-wrapper"> - <div class="col s6"> - <h3 id="text" class="valign center w100">0</h3> - </div> - <div class="col s6"> - <canvas id="gauge" width="150" height="60" - class="valign center"></canvas> - </div> - </div> - <textarea id="query">MATCH (n:Person) RETURN n</textarea> - </div> - <div id="q-0-2" class="card"> - <div class="qps valign-wrapper"> - <div class="col s6"> - <h3 id="text" class="valign center w100">0</h3> - </div> - <div class="col s6"> - <canvas id="gauge" width="150" height="60" - class="valign center"></canvas> - </div> - </div> - <textarea id="query">MATCH (n:Person) RETURN n</textarea> - </div> - <div id="q-0-3" class="card"> - <div class="qps valign-wrapper"> - <div class="col s6"> - <h3 id="text" class="valign center w100">0</h3> - </div> - <div class="col s6"> - <canvas id="gauge" width="150" height="60" - class="valign center"></canvas> - </div> - </div> - <textarea id="query">MATCH (n:Person) RETURN n</textarea> - </div> - <div id="q-0-4" class="card"> - <div class="qps valign-wrapper"> - <div class="col s6"> - <h3 id="text" class="valign center w100">0</h3> - </div> - <div class="col s6"> - <canvas id="gauge" width="150" height="60" - class="valign center"></canvas> - </div> - </div> - <textarea id="query">MATCH (n:Person) RETURN n</textarea> - </div> - </div> - - <!-- the graph --> - <div class="col s8"> - <div class="card"> - <div class="card-content"> - <div id="chart" style="height: 750px;"> - <svg></svg> - </div> - </div> - </div> - </div> - - <!-- memgraph cards --> - <div class="col s2"> - <div id="q-1-0" class="card"> - <div class="qps valign-wrapper"> - <div class="col s6"> - <h3 id="text" class="valign center w100">0</h3> - </div> - <div class="col s6"> - <canvas id="gauge" width="150" height="60" - class="valign center"></canvas> - </div> - </div> - <textarea id="query">MATCH (n:Person) RETURN n</textarea> - </div> - <div id="q-1-1" class="card"> - <div class="qps valign-wrapper"> - <div class="col s6"> - <h3 id="text" class="valign center w100">0</h3> - </div> - <div class="col s6"> - <canvas id="gauge" width="150" height="60" - class="valign center"></canvas> - </div> - </div> - <textarea id="query">MATCH (n:Person) RETURN n</textarea> - </div> - <div id="q-1-2" class="card"> - <div class="qps valign-wrapper"> - <div class="col s6"> - <h3 id="text" class="valign center w100">0</h3> - </div> - <div class="col s6"> - <canvas id="gauge" width="150" height="60" - class="valign center"></canvas> - </div> - </div> - <textarea id="query">MATCH (n:Person) RETURN n</textarea> - </div> - <div id="q-1-3" class="card"> - <div class="qps valign-wrapper"> - <div class="col s6"> - <h3 id="text" class="valign center w100">0</h3> - </div> - <div class="col s6"> - <canvas id="gauge" width="150" height="60" - class="valign center"></canvas> - </div> - </div> - <textarea id="query">MATCH (n:Person) RETURN n</textarea> - </div> - <div id="q-1-4" class="card"> - <div class="qps valign-wrapper"> - <div class="col s6"> - <h3 id="text" class="valign center w100">0</h3> - </div> - <div class="col s6"> - <canvas id="gauge" width="150" height="60" - class="valign center"></canvas> - </div> - </div> - <textarea id="query">MATCH (n:Person) RETURN n</textarea> - </div> - </div> - </div> - - <script type="text/javascript" src="https://code.jquery.com/jquery-2.1.1.min.js"></script> - <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.5/js/materialize.min.js"></script> - <script type="text/javascript" src="http://bernii.github.io/gauge.js/dist/gauge.min.js"></script> - <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script> - <script src="https://cdn.rawgit.com/novus/nvd3/v1.8.1/build/nv.d3.min.js"></script> - <script src="cypher/codemirror.js"></script> - <script src="cypher/cypher.js"></script> - <script src="demo.js"></script> - -</body> diff --git a/src/demo/static/demo.js b/src/demo/static/demo.js deleted file mode 100644 index 7fd95dc2c..000000000 --- a/src/demo/static/demo.js +++ /dev/null @@ -1,308 +0,0 @@ -(() => { - 'use strict'; - - class QpsGauge { - constructor(canvas) { - this.gauge = new Gauge(canvas).setOptions({ - lines: 12, // The number of lines to draw - angle: 0.07, // The length of each line - lineWidth: 0.27, // The line thickness - pointer: { - length: 0.82, // The radius of the inner circle - strokeWidth: 0.073, // The rotation offset - color: '#000' // Fill color - }, - // If true, the pointer will not go past the end of the gauge - limitMax: 'true', - strokeColor: '#e0e0e0', // to see which ones work best for you - generateGradient: true, - percentColors: [[0.0, '#d32f2f'], [0.5, '#ffee58'], [1.0, '#388e3c']], - }); - - this.gauge.animationSpeed = 1; - } - - set(value) { - this.gauge.set(value); - } - - setMax(value) { - this.gauge.maxValue = this.maxValue = value; - } - - getMax() { - return this.maxValue; - } - } - - class CypherQuery { - constructor(textarea) { - this.textarea = textarea; - this.editor = CodeMirror.fromTextArea(this.textarea, { - height: 0, - lineNumbers: true, - mode: 'application/x-cypher-query', - indentWithTabs: false, - smartIndent: true, - matchBrackets: true, - theme: 'neo', - viewportMargin: Infinity - }); - } - - set(value) { - this.editor.getDoc().setValue(value); - } - - get(separator) { - separator = separator ? separator : ' '; - this.editor.getDoc().getValue(separator); - } - } - - class QpsText { - constructor(element) { - this.element = element; - } - - get() { - $(this.element).text(); - } - - set(text) { - $(this.element).text(text); - } - } - - class QueryCard { - constructor(card, maxQps, value) { - this.card = card; - this.maxQps = maxQps; - - value = value ? value : 1; - - this.text = new QpsText($(card).find('#text')[0]); - this.gauge = new QpsGauge($(card).find('#gauge')[0]); - this.query = new CypherQuery($(card).find('#query')[0]); - - this.gauge.setMax(maxQps + 1); - this.gauge.animationSpeed = 1; - this.gauge.set(value); - } - - set_value(value) { - this.text.set(value); - this.gauge.set(value); - } - - set_query(query) { - this.query.set(query); - } - } - - // put \n on module 2 space positions - var put_new_line_mod_2 = function(array) { - let join_array = array.map(function(o, i) { - if (i % 2 === 0) - return ' '; - else - return '\n'; - }); - join_array.pop(); - return array.map(function(v,i) { - return [v, join_array[i]]; - }).reduce(function(a,b) { - return a.concat(b); - }); - }; - - // -- variable part ---- - let running = false; - let value = 0; - let maxQps = 10000; - let memgraphCards = []; - let neo4jCards = []; - let memgraphSec = 0; - let neo4jSec = 0; - let memgraphLine = []; - let neo4jLine = []; - var queries = [ - "CREATE (n:Item{id:@}) RETURN n", - "MATCH (n:Item{id:#}),(m:Item{id:#}) CREATE (n)-[r:test]->(m) RETURN r", - "MATCH (n:Item{id:#}) SET n.prop=# RETURN n", - "MATCH (n:Item{id:#}) RETURN n", - "MATCH (n:Item{id:#})-[r]->(m) RETURN count(r)" - ]; - var params = { - host: "localhost", - port: "7474", - connections: 2, - duration: 1, - queries: queries - }; - // ----------------------- - - // server control functions - var start = function() { - $.ajax({url:'/start', type:"POST", success: function(data){}}); - }; - var stop = function() { - $.ajax({url:'/stop', type:"POST", success: function(data){}}); - }; - var registerParams = function(f) { - $.ajax({ - url:'/params', type:"POST", data:JSON.stringify(params), - contentType:"application/json; charset=utf-8", - success: function(data){ - f(); - } - }); - }; - registerParams(); - - // setup cards - queries.forEach(function(query, i) { - query = put_new_line_mod_2(query.split(" ")).join(''); - neo4jCards.push(new QueryCard($('#q-0-' + i.toString())[0], maxQps)); - memgraphCards.push(new QueryCard($('#q-1-' + i.toString())[0], maxQps)); - neo4jCards[i].set_query(query); - memgraphCards[i].set_query(query); - }); - - // start stop button - $("#run-neo4j").click(function() { - running = !running; - if (running) { - $(this).text('Stop Neo4j'); - let hostname_port = $("#neo4j_url").val().split(":"); - params.host = hostname_port[0]; - params.port = hostname_port[1]; - params.connections = 2; - registerParams(function() { - start(); - updateNeo4j(); - }); - } - if (!running) { - $(this).text('Start Neo4j'); - stop(); - } - }); - - // start stop button - $("#run-memgraph").click(function() { - running = !running; - if (running) { - $(this).text('Stop Memgraph'); - let hostname_port = $("#memgraph_url").val().split(":"); - params.host = hostname_port[0]; - params.port = hostname_port[1]; - params.connections = 4; - registerParams(function() { - start(); - updateMemgraph(); - }); - } - if (!running) { - $(this).text('Start Memgraph'); - stop(); - } - }); - - // update only line on the graph - var updateGraph = function() { - let newData = [{ - values: memgraphLine, - key: 'Memgraph', - color: '#ff0000', - strokeWidth: 3 - }, { - values: neo4jLine, - key: 'Neo4j', - color: '#0000ff', - strokeWidth: 3 - }]; - chartData.datum(newData).transition().duration(500).call(chart); - }; - - // update - function updateNeo4j() { - if (!running) { - stop(); - return; - } - setTimeout(() => { - $.ajax({ - url:'/stats', type:"GET", - success: function(data){ - if (!data || !data.total || !data.per_query) - return; - - neo4jSec = neo4jSec + 1; - neo4jLine.push({x: neo4jSec, y: data.total}); - data.per_query.forEach(function(speed, i) { - neo4jCards[i].set_value(Math.round(speed)); - }); - updateGraph(); - } - }); - updateNeo4j(); - }, 1000); - } - - // update - function updateMemgraph() { - if (!running) { - stop(); - return; - } - setTimeout(() => { - $.ajax({ - url:'/stats', type:"GET", - success: function(data){ - if (!data || !data.total || !data.per_query) - return; - - memgraphSec = memgraphSec + 1; - memgraphLine.push({x: memgraphSec, y: data.total}); - data.per_query.forEach(function(speed, i) { - memgraphCards[i].set_value(Math.round(speed)); - }); - updateGraph(); - } - }); - updateMemgraph(); - }, 1000); - } - - // graph init - var chart; - var chartData; - nv.addGraph(function() { - chart = nv.models.lineChart() - .interpolate('basis') - .useInteractiveGuideline(true) - .showLegend(true) - .showYAxis(true) - .showXAxis(true); - - chart.xAxis - .axisLabel('Time (s)') - .tickFormat(d3.format(',r')); - - chart.yAxis - .axisLabel('QPS') - .tickFormat(d3.format('f')); - - chart.forceY([0, 50000]); - - chartData = d3.select('#chart svg') - .datum([]); - chartData.call(chart); - - chart.update(); - nv.utils.windowResize(function() { chart.update(); }); - return chart; - }); - -})(); diff --git a/src/demo/static/sigmajs/captors/sigma.captors.mouse.js b/src/demo/static/sigmajs/captors/sigma.captors.mouse.js deleted file mode 100644 index d3a270c9f..000000000 --- a/src/demo/static/sigmajs/captors/sigma.captors.mouse.js +++ /dev/null @@ -1,395 +0,0 @@ -;(function(undefined) { - 'use strict'; - - if (typeof sigma === 'undefined') - throw 'sigma is not declared'; - - // Initialize packages: - sigma.utils.pkg('sigma.captors'); - - /** - * The user inputs default captor. It deals with mouse events, keyboards - * events and touch events. - * - * @param {DOMElement} target The DOM element where the listeners will be - * bound. - * @param {camera} camera The camera related to the target. - * @param {configurable} settings The settings function. - * @return {sigma.captor} The fresh new captor instance. - */ - sigma.captors.mouse = function(target, camera, settings) { - var _self = this, - _target = target, - _camera = camera, - _settings = settings, - - // CAMERA MANAGEMENT: - // ****************** - // The camera position when the user starts dragging: - _startCameraX, - _startCameraY, - _startCameraAngle, - - // The latest stage position: - _lastCameraX, - _lastCameraY, - _lastCameraAngle, - _lastCameraRatio, - - // MOUSE MANAGEMENT: - // ***************** - // The mouse position when the user starts dragging: - _startMouseX, - _startMouseY, - - _isMouseDown, - _isMoving, - _hasDragged, - _downStartTime, - _movingTimeoutId; - - sigma.classes.dispatcher.extend(this); - - sigma.utils.doubleClick(_target, 'click', _doubleClickHandler); - _target.addEventListener('DOMMouseScroll', _wheelHandler, false); - _target.addEventListener('mousewheel', _wheelHandler, false); - _target.addEventListener('mousemove', _moveHandler, false); - _target.addEventListener('mousedown', _downHandler, false); - _target.addEventListener('click', _clickHandler, false); - _target.addEventListener('mouseout', _outHandler, false); - document.addEventListener('mouseup', _upHandler, false); - - - - - /** - * This method unbinds every handlers that makes the captor work. - */ - this.kill = function() { - sigma.utils.unbindDoubleClick(_target, 'click'); - _target.removeEventListener('DOMMouseScroll', _wheelHandler); - _target.removeEventListener('mousewheel', _wheelHandler); - _target.removeEventListener('mousemove', _moveHandler); - _target.removeEventListener('mousedown', _downHandler); - _target.removeEventListener('click', _clickHandler); - _target.removeEventListener('mouseout', _outHandler); - document.removeEventListener('mouseup', _upHandler); - }; - - - - - // MOUSE EVENTS: - // ************* - - /** - * The handler listening to the 'move' mouse event. It will effectively - * drag the graph. - * - * @param {event} e A mouse event. - */ - function _moveHandler(e) { - var x, - y, - pos; - - // Dispatch event: - if (_settings('mouseEnabled')) - _self.dispatchEvent('mousemove', { - x: sigma.utils.getX(e) - sigma.utils.getWidth(e) / 2, - y: sigma.utils.getY(e) - sigma.utils.getHeight(e) / 2, - clientX: e.clientX, - clientY: e.clientY, - ctrlKey: e.ctrlKey, - metaKey: e.metaKey, - altKey: e.altKey, - shiftKey: e.shiftKey - }); - - if (_settings('mouseEnabled') && _isMouseDown) { - _isMoving = true; - _hasDragged = true; - - if (_movingTimeoutId) - clearTimeout(_movingTimeoutId); - - _movingTimeoutId = setTimeout(function() { - _isMoving = false; - }, _settings('dragTimeout')); - - sigma.misc.animation.killAll(_camera); - - _camera.isMoving = true; - pos = _camera.cameraPosition( - sigma.utils.getX(e) - _startMouseX, - sigma.utils.getY(e) - _startMouseY, - true - ); - - x = _startCameraX - pos.x; - y = _startCameraY - pos.y; - - if (x !== _camera.x || y !== _camera.y) { - _lastCameraX = _camera.x; - _lastCameraY = _camera.y; - - _camera.goTo({ - x: x, - y: y - }); - } - - if (e.preventDefault) - e.preventDefault(); - else - e.returnValue = false; - - e.stopPropagation(); - return false; - } - } - - /** - * The handler listening to the 'up' mouse event. It will stop dragging the - * graph. - * - * @param {event} e A mouse event. - */ - function _upHandler(e) { - if (_settings('mouseEnabled') && _isMouseDown) { - _isMouseDown = false; - if (_movingTimeoutId) - clearTimeout(_movingTimeoutId); - - _camera.isMoving = false; - - var x = sigma.utils.getX(e), - y = sigma.utils.getY(e); - - if (_isMoving) { - sigma.misc.animation.killAll(_camera); - sigma.misc.animation.camera( - _camera, - { - x: _camera.x + - _settings('mouseInertiaRatio') * (_camera.x - _lastCameraX), - y: _camera.y + - _settings('mouseInertiaRatio') * (_camera.y - _lastCameraY) - }, - { - easing: 'quadraticOut', - duration: _settings('mouseInertiaDuration') - } - ); - } else if ( - _startMouseX !== x || - _startMouseY !== y - ) - _camera.goTo({ - x: _camera.x, - y: _camera.y - }); - - _self.dispatchEvent('mouseup', { - x: x - sigma.utils.getWidth(e) / 2, - y: y - sigma.utils.getHeight(e) / 2, - clientX: e.clientX, - clientY: e.clientY, - ctrlKey: e.ctrlKey, - metaKey: e.metaKey, - altKey: e.altKey, - shiftKey: e.shiftKey - }); - - // Update _isMoving flag: - _isMoving = false; - } - } - - /** - * The handler listening to the 'down' mouse event. It will start observing - * the mouse position for dragging the graph. - * - * @param {event} e A mouse event. - */ - function _downHandler(e) { - if (_settings('mouseEnabled')) { - _startCameraX = _camera.x; - _startCameraY = _camera.y; - - _lastCameraX = _camera.x; - _lastCameraY = _camera.y; - - _startMouseX = sigma.utils.getX(e); - _startMouseY = sigma.utils.getY(e); - - _hasDragged = false; - _downStartTime = (new Date()).getTime(); - - switch (e.which) { - case 2: - // Middle mouse button pressed - // Do nothing. - break; - case 3: - // Right mouse button pressed - _self.dispatchEvent('rightclick', { - x: _startMouseX - sigma.utils.getWidth(e) / 2, - y: _startMouseY - sigma.utils.getHeight(e) / 2, - clientX: e.clientX, - clientY: e.clientY, - ctrlKey: e.ctrlKey, - metaKey: e.metaKey, - altKey: e.altKey, - shiftKey: e.shiftKey - }); - break; - // case 1: - default: - // Left mouse button pressed - _isMouseDown = true; - - _self.dispatchEvent('mousedown', { - x: _startMouseX - sigma.utils.getWidth(e) / 2, - y: _startMouseY - sigma.utils.getHeight(e) / 2, - clientX: e.clientX, - clientY: e.clientY, - ctrlKey: e.ctrlKey, - metaKey: e.metaKey, - altKey: e.altKey, - shiftKey: e.shiftKey - }); - } - } - } - - /** - * The handler listening to the 'out' mouse event. It will just redispatch - * the event. - * - * @param {event} e A mouse event. - */ - function _outHandler(e) { - if (_settings('mouseEnabled')) - _self.dispatchEvent('mouseout'); - } - - /** - * The handler listening to the 'click' mouse event. It will redispatch the - * click event, but with normalized X and Y coordinates. - * - * @param {event} e A mouse event. - */ - function _clickHandler(e) { - if (_settings('mouseEnabled')) - _self.dispatchEvent('click', { - x: sigma.utils.getX(e) - sigma.utils.getWidth(e) / 2, - y: sigma.utils.getY(e) - sigma.utils.getHeight(e) / 2, - clientX: e.clientX, - clientY: e.clientY, - ctrlKey: e.ctrlKey, - metaKey: e.metaKey, - altKey: e.altKey, - shiftKey: e.shiftKey, - isDragging: - (((new Date()).getTime() - _downStartTime) > 100) && - _hasDragged - }); - - if (e.preventDefault) - e.preventDefault(); - else - e.returnValue = false; - - e.stopPropagation(); - return false; - } - - /** - * The handler listening to the double click custom event. It will - * basically zoom into the graph. - * - * @param {event} e A mouse event. - */ - function _doubleClickHandler(e) { - var pos, - ratio, - animation; - - if (_settings('mouseEnabled')) { - ratio = 1 / _settings('doubleClickZoomingRatio'); - - _self.dispatchEvent('doubleclick', { - x: _startMouseX - sigma.utils.getWidth(e) / 2, - y: _startMouseY - sigma.utils.getHeight(e) / 2, - clientX: e.clientX, - clientY: e.clientY, - ctrlKey: e.ctrlKey, - metaKey: e.metaKey, - altKey: e.altKey, - shiftKey: e.shiftKey - }); - - if (_settings('doubleClickEnabled')) { - pos = _camera.cameraPosition( - sigma.utils.getX(e) - sigma.utils.getWidth(e) / 2, - sigma.utils.getY(e) - sigma.utils.getHeight(e) / 2, - true - ); - - animation = { - duration: _settings('doubleClickZoomDuration') - }; - - sigma.utils.zoomTo(_camera, pos.x, pos.y, ratio, animation); - } - - if (e.preventDefault) - e.preventDefault(); - else - e.returnValue = false; - - e.stopPropagation(); - return false; - } - } - - /** - * The handler listening to the 'wheel' mouse event. It will basically zoom - * in or not into the graph. - * - * @param {event} e A mouse event. - */ - function _wheelHandler(e) { - var pos, - ratio, - animation; - - if (_settings('mouseEnabled') && _settings('mouseWheelEnabled')) { - ratio = sigma.utils.getDelta(e) > 0 ? - 1 / _settings('zoomingRatio') : - _settings('zoomingRatio'); - - pos = _camera.cameraPosition( - sigma.utils.getX(e) - sigma.utils.getWidth(e) / 2, - sigma.utils.getY(e) - sigma.utils.getHeight(e) / 2, - true - ); - - animation = { - duration: _settings('mouseZoomDuration') - }; - - sigma.utils.zoomTo(_camera, pos.x, pos.y, ratio, animation); - - if (e.preventDefault) - e.preventDefault(); - else - e.returnValue = false; - - e.stopPropagation(); - return false; - } - } - }; -}).call(this); diff --git a/src/demo/static/sigmajs/captors/sigma.captors.touch.js b/src/demo/static/sigmajs/captors/sigma.captors.touch.js deleted file mode 100644 index b63b50aed..000000000 --- a/src/demo/static/sigmajs/captors/sigma.captors.touch.js +++ /dev/null @@ -1,430 +0,0 @@ -;(function(undefined) { - 'use strict'; - - if (typeof sigma === 'undefined') - throw 'sigma is not declared'; - - // Initialize packages: - sigma.utils.pkg('sigma.captors'); - - /** - * The user inputs default captor. It deals with mouse events, keyboards - * events and touch events. - * - * @param {DOMElement} target The DOM element where the listeners will be - * bound. - * @param {camera} camera The camera related to the target. - * @param {configurable} settings The settings function. - * @return {sigma.captor} The fresh new captor instance. - */ - sigma.captors.touch = function(target, camera, settings) { - var _self = this, - _target = target, - _camera = camera, - _settings = settings, - - // CAMERA MANAGEMENT: - // ****************** - // The camera position when the user starts dragging: - _startCameraX, - _startCameraY, - _startCameraAngle, - _startCameraRatio, - - // The latest stage position: - _lastCameraX, - _lastCameraY, - _lastCameraAngle, - _lastCameraRatio, - - // TOUCH MANAGEMENT: - // ***************** - // Touches that are down: - _downTouches = [], - - _startTouchX0, - _startTouchY0, - _startTouchX1, - _startTouchY1, - _startTouchAngle, - _startTouchDistance, - - _touchMode, - - _isMoving, - _doubleTap, - _movingTimeoutId; - - sigma.classes.dispatcher.extend(this); - - sigma.utils.doubleClick(_target, 'touchstart', _doubleTapHandler); - _target.addEventListener('touchstart', _handleStart, false); - _target.addEventListener('touchend', _handleLeave, false); - _target.addEventListener('touchcancel', _handleLeave, false); - _target.addEventListener('touchleave', _handleLeave, false); - _target.addEventListener('touchmove', _handleMove, false); - - function position(e) { - var offset = sigma.utils.getOffset(_target); - - return { - x: e.pageX - offset.left, - y: e.pageY - offset.top - }; - } - - - - - /** - * This method unbinds every handlers that makes the captor work. - */ - this.kill = function() { - sigma.utils.unbindDoubleClick(_target, 'touchstart'); - _target.addEventListener('touchstart', _handleStart); - _target.addEventListener('touchend', _handleLeave); - _target.addEventListener('touchcancel', _handleLeave); - _target.addEventListener('touchleave', _handleLeave); - _target.addEventListener('touchmove', _handleMove); - }; - - - - - // TOUCH EVENTS: - // ************* - /** - * The handler listening to the 'touchstart' event. It will set the touch - * mode ("_touchMode") and start observing the user touch moves. - * - * @param {event} e A touch event. - */ - function _handleStart(e) { - if (_settings('touchEnabled')) { - var x0, - x1, - y0, - y1, - pos0, - pos1; - - _downTouches = e.touches; - - switch (_downTouches.length) { - case 1: - _camera.isMoving = true; - _touchMode = 1; - - _startCameraX = _camera.x; - _startCameraY = _camera.y; - - _lastCameraX = _camera.x; - _lastCameraY = _camera.y; - - pos0 = position(_downTouches[0]); - _startTouchX0 = pos0.x; - _startTouchY0 = pos0.y; - - break; - case 2: - _camera.isMoving = true; - _touchMode = 2; - - pos0 = position(_downTouches[0]); - pos1 = position(_downTouches[1]); - x0 = pos0.x; - y0 = pos0.y; - x1 = pos1.x; - y1 = pos1.y; - - _lastCameraX = _camera.x; - _lastCameraY = _camera.y; - - _startCameraAngle = _camera.angle; - _startCameraRatio = _camera.ratio; - - _startCameraX = _camera.x; - _startCameraY = _camera.y; - - _startTouchX0 = x0; - _startTouchY0 = y0; - _startTouchX1 = x1; - _startTouchY1 = y1; - - _startTouchAngle = Math.atan2( - _startTouchY1 - _startTouchY0, - _startTouchX1 - _startTouchX0 - ); - _startTouchDistance = Math.sqrt( - Math.pow(_startTouchY1 - _startTouchY0, 2) + - Math.pow(_startTouchX1 - _startTouchX0, 2) - ); - - e.preventDefault(); - return false; - } - } - } - - /** - * The handler listening to the 'touchend', 'touchcancel' and 'touchleave' - * event. It will update the touch mode if there are still at least one - * finger, and stop dragging else. - * - * @param {event} e A touch event. - */ - function _handleLeave(e) { - if (_settings('touchEnabled')) { - _downTouches = e.touches; - var inertiaRatio = _settings('touchInertiaRatio'); - - if (_movingTimeoutId) { - _isMoving = false; - clearTimeout(_movingTimeoutId); - } - - switch (_touchMode) { - case 2: - if (e.touches.length === 1) { - _handleStart(e); - - e.preventDefault(); - break; - } - /* falls through */ - case 1: - _camera.isMoving = false; - _self.dispatchEvent('stopDrag'); - - if (_isMoving) { - _doubleTap = false; - sigma.misc.animation.camera( - _camera, - { - x: _camera.x + - inertiaRatio * (_camera.x - _lastCameraX), - y: _camera.y + - inertiaRatio * (_camera.y - _lastCameraY) - }, - { - easing: 'quadraticOut', - duration: _settings('touchInertiaDuration') - } - ); - } - - _isMoving = false; - _touchMode = 0; - break; - } - } - } - - /** - * The handler listening to the 'touchmove' event. It will effectively drag - * the graph, and eventually zooms and turn it if the user is using two - * fingers. - * - * @param {event} e A touch event. - */ - function _handleMove(e) { - if (!_doubleTap && _settings('touchEnabled')) { - var x0, - x1, - y0, - y1, - cos, - sin, - end, - pos0, - pos1, - diff, - start, - dAngle, - dRatio, - newStageX, - newStageY, - newStageRatio, - newStageAngle; - - _downTouches = e.touches; - _isMoving = true; - - if (_movingTimeoutId) - clearTimeout(_movingTimeoutId); - - _movingTimeoutId = setTimeout(function() { - _isMoving = false; - }, _settings('dragTimeout')); - - switch (_touchMode) { - case 1: - pos0 = position(_downTouches[0]); - x0 = pos0.x; - y0 = pos0.y; - - diff = _camera.cameraPosition( - x0 - _startTouchX0, - y0 - _startTouchY0, - true - ); - - newStageX = _startCameraX - diff.x; - newStageY = _startCameraY - diff.y; - - if (newStageX !== _camera.x || newStageY !== _camera.y) { - _lastCameraX = _camera.x; - _lastCameraY = _camera.y; - - _camera.goTo({ - x: newStageX, - y: newStageY - }); - - _self.dispatchEvent('mousemove', { - x: pos0.x - sigma.utils.getWidth(e) / 2, - y: pos0.y - sigma.utils.getHeight(e) / 2, - clientX: e.clientX, - clientY: e.clientY, - ctrlKey: e.ctrlKey, - metaKey: e.metaKey, - altKey: e.altKey, - shiftKey: e.shiftKey - }); - - _self.dispatchEvent('drag'); - } - break; - case 2: - pos0 = position(_downTouches[0]); - pos1 = position(_downTouches[1]); - x0 = pos0.x; - y0 = pos0.y; - x1 = pos1.x; - y1 = pos1.y; - - start = _camera.cameraPosition( - (_startTouchX0 + _startTouchX1) / 2 - - sigma.utils.getWidth(e) / 2, - (_startTouchY0 + _startTouchY1) / 2 - - sigma.utils.getHeight(e) / 2, - true - ); - end = _camera.cameraPosition( - (x0 + x1) / 2 - sigma.utils.getWidth(e) / 2, - (y0 + y1) / 2 - sigma.utils.getHeight(e) / 2, - true - ); - - dAngle = Math.atan2(y1 - y0, x1 - x0) - _startTouchAngle; - dRatio = Math.sqrt( - Math.pow(y1 - y0, 2) + Math.pow(x1 - x0, 2) - ) / _startTouchDistance; - - // Translation: - x0 = start.x; - y0 = start.y; - - // Homothetic transformation: - newStageRatio = _startCameraRatio / dRatio; - x0 = x0 * dRatio; - y0 = y0 * dRatio; - - // Rotation: - newStageAngle = _startCameraAngle - dAngle; - cos = Math.cos(-dAngle); - sin = Math.sin(-dAngle); - x1 = x0 * cos + y0 * sin; - y1 = y0 * cos - x0 * sin; - x0 = x1; - y0 = y1; - - // Finalize: - newStageX = x0 - end.x + _startCameraX; - newStageY = y0 - end.y + _startCameraY; - - if ( - newStageRatio !== _camera.ratio || - newStageAngle !== _camera.angle || - newStageX !== _camera.x || - newStageY !== _camera.y - ) { - _lastCameraX = _camera.x; - _lastCameraY = _camera.y; - _lastCameraAngle = _camera.angle; - _lastCameraRatio = _camera.ratio; - - _camera.goTo({ - x: newStageX, - y: newStageY, - angle: newStageAngle, - ratio: newStageRatio - }); - - _self.dispatchEvent('drag'); - } - - break; - } - - e.preventDefault(); - return false; - } - } - - /** - * The handler listening to the double tap custom event. It will - * basically zoom into the graph. - * - * @param {event} e A touch event. - */ - function _doubleTapHandler(e) { - var pos, - ratio, - animation; - - if (e.touches && e.touches.length === 1 && _settings('touchEnabled')) { - _doubleTap = true; - - ratio = 1 / _settings('doubleClickZoomingRatio'); - - pos = position(e.touches[0]); - _self.dispatchEvent('doubleclick', { - x: pos.x - sigma.utils.getWidth(e) / 2, - y: pos.y - sigma.utils.getHeight(e) / 2, - clientX: e.clientX, - clientY: e.clientY, - ctrlKey: e.ctrlKey, - metaKey: e.metaKey, - altKey: e.altKey, - shiftKey: e.shiftKey - }); - - if (_settings('doubleClickEnabled')) { - pos = _camera.cameraPosition( - pos.x - sigma.utils.getWidth(e) / 2, - pos.y - sigma.utils.getHeight(e) / 2, - true - ); - - animation = { - duration: _settings('doubleClickZoomDuration'), - onComplete: function() { - _doubleTap = false; - } - }; - - sigma.utils.zoomTo(_camera, pos.x, pos.y, ratio, animation); - } - - if (e.preventDefault) - e.preventDefault(); - else - e.returnValue = false; - - e.stopPropagation(); - return false; - } - } - }; -}).call(this); diff --git a/src/demo/static/sigmajs/classes/sigma.classes.camera.js b/src/demo/static/sigmajs/classes/sigma.classes.camera.js deleted file mode 100644 index f4a86b1de..000000000 --- a/src/demo/static/sigmajs/classes/sigma.classes.camera.js +++ /dev/null @@ -1,240 +0,0 @@ -;(function(undefined) { - 'use strict'; - - if (typeof sigma === 'undefined') - throw 'sigma is not declared'; - - sigma.utils.pkg('sigma.classes'); - - /** - * The camera constructor. It just initializes its attributes and methods. - * - * @param {string} id The id. - * @param {sigma.classes.graph} graph The graph. - * @param {configurable} settings The settings function. - * @param {?object} options Eventually some overriding options. - * @return {camera} Returns the fresh new camera instance. - */ - sigma.classes.camera = function(id, graph, settings, options) { - sigma.classes.dispatcher.extend(this); - - Object.defineProperty(this, 'graph', { - value: graph - }); - Object.defineProperty(this, 'id', { - value: id - }); - Object.defineProperty(this, 'readPrefix', { - value: 'read_cam' + id + ':' - }); - Object.defineProperty(this, 'prefix', { - value: 'cam' + id + ':' - }); - - this.x = 0; - this.y = 0; - this.ratio = 1; - this.angle = 0; - this.isAnimated = false; - this.settings = (typeof options === 'object' && options) ? - settings.embedObject(options) : - settings; - }; - - /** - * Updates the camera position. - * - * @param {object} coordinates The new coordinates object. - * @return {camera} Returns the camera. - */ - sigma.classes.camera.prototype.goTo = function(coordinates) { - if (!this.settings('enableCamera')) - return this; - - var i, - l, - c = coordinates || {}, - keys = ['x', 'y', 'ratio', 'angle']; - - for (i = 0, l = keys.length; i < l; i++) - if (c[keys[i]] !== undefined) { - if (typeof c[keys[i]] === 'number' && !isNaN(c[keys[i]])) - this[keys[i]] = c[keys[i]]; - else - throw 'Value for "' + keys[i] + '" is not a number.'; - } - - this.dispatchEvent('coordinatesUpdated'); - return this; - }; - - /** - * This method takes a graph and computes for each node and edges its - * coordinates relatively to the center of the camera. Basically, it will - * compute the coordinates that will be used by the graphic renderers. - * - * Since it should be possible to use different cameras and different - * renderers, it is possible to specify a prefix to put before the new - * coordinates (to get something like "node.camera1_x") - * - * @param {?string} read The prefix of the coordinates to read. - * @param {?string} write The prefix of the coordinates to write. - * @param {?object} options Eventually an object of options. Those can be: - * - A restricted nodes array. - * - A restricted edges array. - * - A width. - * - A height. - * @return {camera} Returns the camera. - */ - sigma.classes.camera.prototype.applyView = function(read, write, options) { - options = options || {}; - write = write !== undefined ? write : this.prefix; - read = read !== undefined ? read : this.readPrefix; - - var nodes = options.nodes || this.graph.nodes(), - edges = options.edges || this.graph.edges(); - - var i, - l, - node, - cos = Math.cos(this.angle), - sin = Math.sin(this.angle), - nodeRatio = Math.pow(this.ratio, this.settings('nodesPowRatio')), - edgeRatio = Math.pow(this.ratio, this.settings('edgesPowRatio')); - - for (i = 0, l = nodes.length; i < l; i++) { - node = nodes[i]; - node[write + 'x'] = - ( - ((node[read + 'x'] || 0) - this.x) * cos + - ((node[read + 'y'] || 0) - this.y) * sin - ) / this.ratio + (options.width || 0) / 2; - node[write + 'y'] = - ( - ((node[read + 'y'] || 0) - this.y) * cos - - ((node[read + 'x'] || 0) - this.x) * sin - ) / this.ratio + (options.height || 0) / 2; - node[write + 'size'] = - (node[read + 'size'] || 0) / - nodeRatio; - } - - for (i = 0, l = edges.length; i < l; i++) { - edges[i][write + 'size'] = - (edges[i][read + 'size'] || 0) / - edgeRatio; - } - - return this; - }; - - /** - * This function converts the coordinates of a point from the frame of the - * camera to the frame of the graph. - * - * @param {number} x The X coordinate of the point in the frame of the - * camera. - * @param {number} y The Y coordinate of the point in the frame of the - * camera. - * @return {object} The point coordinates in the frame of the graph. - */ - sigma.classes.camera.prototype.graphPosition = function(x, y, vector) { - var X = 0, - Y = 0, - cos = Math.cos(this.angle), - sin = Math.sin(this.angle); - - // Revert the origin differential vector: - if (!vector) { - X = - (this.x * cos + this.y * sin) / this.ratio; - Y = - (this.y * cos - this.x * sin) / this.ratio; - } - - return { - x: (x * cos + y * sin) / this.ratio + X, - y: (y * cos - x * sin) / this.ratio + Y - }; - }; - - /** - * This function converts the coordinates of a point from the frame of the - * graph to the frame of the camera. - * - * @param {number} x The X coordinate of the point in the frame of the - * graph. - * @param {number} y The Y coordinate of the point in the frame of the - * graph. - * @return {object} The point coordinates in the frame of the camera. - */ - sigma.classes.camera.prototype.cameraPosition = function(x, y, vector) { - var X = 0, - Y = 0, - cos = Math.cos(this.angle), - sin = Math.sin(this.angle); - - // Revert the origin differential vector: - if (!vector) { - X = - (this.x * cos + this.y * sin) / this.ratio; - Y = - (this.y * cos - this.x * sin) / this.ratio; - } - - return { - x: ((x - X) * cos - (y - Y) * sin) * this.ratio, - y: ((y - Y) * cos + (x - X) * sin) * this.ratio - }; - }; - - /** - * This method returns the transformation matrix of the camera. This is - * especially useful to apply the camera view directly in shaders, in case of - * WebGL rendering. - * - * @return {array} The transformation matrix. - */ - sigma.classes.camera.prototype.getMatrix = function() { - var scale = sigma.utils.matrices.scale(1 / this.ratio), - rotation = sigma.utils.matrices.rotation(this.angle), - translation = sigma.utils.matrices.translation(-this.x, -this.y), - matrix = sigma.utils.matrices.multiply( - translation, - sigma.utils.matrices.multiply( - rotation, - scale - ) - ); - - return matrix; - }; - - /** - * Taking a width and a height as parameters, this method returns the - * coordinates of the rectangle representing the camera on screen, in the - * graph's referentiel. - * - * To keep displaying labels of nodes going out of the screen, the method - * keeps a margin around the screen in the returned rectangle. - * - * @param {number} width The width of the screen. - * @param {number} height The height of the screen. - * @return {object} The rectangle as x1, y1, x2 and y2, representing - * two opposite points. - */ - sigma.classes.camera.prototype.getRectangle = function(width, height) { - var widthVect = this.cameraPosition(width, 0, true), - heightVect = this.cameraPosition(0, height, true), - centerVect = this.cameraPosition(width / 2, height / 2, true), - marginX = this.cameraPosition(width / 4, 0, true).x, - marginY = this.cameraPosition(0, height / 4, true).y; - - return { - x1: this.x - centerVect.x - marginX, - y1: this.y - centerVect.y - marginY, - x2: this.x - centerVect.x + marginX + widthVect.x, - y2: this.y - centerVect.y - marginY + widthVect.y, - height: Math.sqrt( - Math.pow(heightVect.x, 2) + - Math.pow(heightVect.y + 2 * marginY, 2) - ) - }; - }; -}).call(this); diff --git a/src/demo/static/sigmajs/classes/sigma.classes.configurable.js b/src/demo/static/sigmajs/classes/sigma.classes.configurable.js deleted file mode 100644 index 09ce1f796..000000000 --- a/src/demo/static/sigmajs/classes/sigma.classes.configurable.js +++ /dev/null @@ -1,116 +0,0 @@ -;(function() { - 'use strict'; - - /** - * This utils aims to facilitate the manipulation of each instance setting. - * Using a function instead of an object brings two main advantages: First, - * it will be easier in the future to catch settings updates through a - * function than an object. Second, giving it a full object will "merge" it - * to the settings object properly, keeping us to have to always add a loop. - * - * @return {configurable} The "settings" function. - */ - var configurable = function() { - var i, - l, - data = {}, - datas = Array.prototype.slice.call(arguments, 0); - - /** - * The method to use to set or get any property of this instance. - * - * @param {string|object} a1 If it is a string and if a2 is undefined, - * then it will return the corresponding - * property. If it is a string and if a2 is - * set, then it will set a2 as the property - * corresponding to a1, and return this. If - * it is an object, then each pair string + - * object(or any other type) will be set as a - * property. - * @param {*?} a2 The new property corresponding to a1 if a1 - * is a string. - * @return {*|configurable} Returns itself or the corresponding - * property. - * - * Polymorphism: - * ************* - * Here are some basic use examples: - * - * > settings = new configurable(); - * > settings('mySetting', 42); - * > settings('mySetting'); // Logs: 42 - * > settings('mySetting', 123); - * > settings('mySetting'); // Logs: 123 - * > settings({mySetting: 456}); - * > settings('mySetting'); // Logs: 456 - * - * Also, it is possible to use the function as a fallback: - * > settings({mySetting: 'abc'}, 'mySetting'); // Logs: 'abc' - * > settings({hisSetting: 'abc'}, 'mySetting'); // Logs: 456 - */ - var settings = function(a1, a2) { - var o, - i, - l, - k; - - if (arguments.length === 1 && typeof a1 === 'string') { - if (data[a1] !== undefined) - return data[a1]; - for (i = 0, l = datas.length; i < l; i++) - if (datas[i][a1] !== undefined) - return datas[i][a1]; - return undefined; - } else if (typeof a1 === 'object' && typeof a2 === 'string') { - return (a1 || {})[a2] !== undefined ? a1[a2] : settings(a2); - } else { - o = (typeof a1 === 'object' && a2 === undefined) ? a1 : {}; - - if (typeof a1 === 'string') - o[a1] = a2; - - for (i = 0, k = Object.keys(o), l = k.length; i < l; i++) - data[k[i]] = o[k[i]]; - - return this; - } - }; - - /** - * This method returns a new configurable function, with new objects - * - * @param {object*} Any number of objects to search in. - * @return {function} Returns the function. Check its documentation to know - * more about how it works. - */ - settings.embedObjects = function() { - var args = datas.concat( - data - ).concat( - Array.prototype.splice.call(arguments, 0) - ); - - return configurable.apply({}, args); - }; - - // Initialize - for (i = 0, l = arguments.length; i < l; i++) - settings(arguments[i]); - - return settings; - }; - - /** - * EXPORT: - * ******* - */ - if (typeof this.sigma !== 'undefined') { - this.sigma.classes = this.sigma.classes || {}; - this.sigma.classes.configurable = configurable; - } else if (typeof exports !== 'undefined') { - if (typeof module !== 'undefined' && module.exports) - exports = module.exports = configurable; - exports.configurable = configurable; - } else - this.configurable = configurable; -}).call(this); diff --git a/src/demo/static/sigmajs/classes/sigma.classes.dispatcher.js b/src/demo/static/sigmajs/classes/sigma.classes.dispatcher.js deleted file mode 100644 index 0ce7dca66..000000000 --- a/src/demo/static/sigmajs/classes/sigma.classes.dispatcher.js +++ /dev/null @@ -1,204 +0,0 @@ -;(function() { - 'use strict'; - - /** - * Dispatcher constructor. - * - * @return {dispatcher} The new dispatcher instance. - */ - var dispatcher = function() { - Object.defineProperty(this, '_handlers', { - value: {} - }); - }; - - - - - /** - * Will execute the handler everytime that the indicated event (or the - * indicated events) will be triggered. - * - * @param {string} events The name of the event (or the events - * separated by spaces). - * @param {function(Object)} handler The handler to bind. - * @return {dispatcher} Returns the instance itself. - */ - dispatcher.prototype.bind = function(events, handler) { - var i, - l, - event, - eArray; - - if ( - arguments.length === 1 && - typeof arguments[0] === 'object' - ) - for (events in arguments[0]) - this.bind(events, arguments[0][events]); - else if ( - arguments.length === 2 && - typeof arguments[1] === 'function' - ) { - eArray = typeof events === 'string' ? events.split(' ') : events; - - for (i = 0, l = eArray.length; i !== l; i += 1) { - event = eArray[i]; - - // Check that event is not '': - if (!event) - continue; - - if (!this._handlers[event]) - this._handlers[event] = []; - - // Using an object instead of directly the handler will make possible - // later to add flags - this._handlers[event].push({ - handler: handler - }); - } - } else - throw 'bind: Wrong arguments.'; - - return this; - }; - - /** - * Removes the handler from a specified event (or specified events). - * - * @param {?string} events The name of the event (or the events - * separated by spaces). If undefined, - * then all handlers are removed. - * @param {?function(object)} handler The handler to unbind. If undefined, - * each handler bound to the event or the - * events will be removed. - * @return {dispatcher} Returns the instance itself. - */ - dispatcher.prototype.unbind = function(events, handler) { - var i, - n, - j, - m, - k, - a, - event, - eArray = typeof events === 'string' ? events.split(' ') : events; - - if (!arguments.length) { - for (k in this._handlers) - delete this._handlers[k]; - return this; - } - - if (handler) { - for (i = 0, n = eArray.length; i !== n; i += 1) { - event = eArray[i]; - if (this._handlers[event]) { - a = []; - for (j = 0, m = this._handlers[event].length; j !== m; j += 1) - if (this._handlers[event][j].handler !== handler) - a.push(this._handlers[event][j]); - - this._handlers[event] = a; - } - - if (this._handlers[event] && this._handlers[event].length === 0) - delete this._handlers[event]; - } - } else - for (i = 0, n = eArray.length; i !== n; i += 1) - delete this._handlers[eArray[i]]; - - return this; - }; - - /** - * Executes each handler bound to the event - * - * @param {string} events The name of the event (or the events separated - * by spaces). - * @param {?object} data The content of the event (optional). - * @return {dispatcher} Returns the instance itself. - */ - dispatcher.prototype.dispatchEvent = function(events, data) { - var i, - n, - j, - m, - a, - event, - eventName, - self = this, - eArray = typeof events === 'string' ? events.split(' ') : events; - - data = data === undefined ? {} : data; - - for (i = 0, n = eArray.length; i !== n; i += 1) { - eventName = eArray[i]; - - if (this._handlers[eventName]) { - event = self.getEvent(eventName, data); - a = []; - - for (j = 0, m = this._handlers[eventName].length; j !== m; j += 1) { - this._handlers[eventName][j].handler(event); - if (!this._handlers[eventName][j].one) - a.push(this._handlers[eventName][j]); - } - - this._handlers[eventName] = a; - } - } - - return this; - }; - - /** - * Return an event object. - * - * @param {string} events The name of the event. - * @param {?object} data The content of the event (optional). - * @return {object} Returns the instance itself. - */ - dispatcher.prototype.getEvent = function(event, data) { - return { - type: event, - data: data || {}, - target: this - }; - }; - - /** - * A useful function to deal with inheritance. It will make the target - * inherit the prototype of the class dispatcher as well as its constructor. - * - * @param {object} target The target. - */ - dispatcher.extend = function(target, args) { - var k; - - for (k in dispatcher.prototype) - if (dispatcher.prototype.hasOwnProperty(k)) - target[k] = dispatcher.prototype[k]; - - dispatcher.apply(target, args); - }; - - - - - /** - * EXPORT: - * ******* - */ - if (typeof this.sigma !== 'undefined') { - this.sigma.classes = this.sigma.classes || {}; - this.sigma.classes.dispatcher = dispatcher; - } else if (typeof exports !== 'undefined') { - if (typeof module !== 'undefined' && module.exports) - exports = module.exports = dispatcher; - exports.dispatcher = dispatcher; - } else - this.dispatcher = dispatcher; -}).call(this); diff --git a/src/demo/static/sigmajs/classes/sigma.classes.edgequad.js b/src/demo/static/sigmajs/classes/sigma.classes.edgequad.js deleted file mode 100644 index fbc5b7fc3..000000000 --- a/src/demo/static/sigmajs/classes/sigma.classes.edgequad.js +++ /dev/null @@ -1,832 +0,0 @@ -;(function(undefined) { - 'use strict'; - - /** - * Sigma Quadtree Module for edges - * =============================== - * - * Author: Sébastien Heymann, - * from the quad of Guillaume Plique (Yomguithereal) - * Version: 0.2 - */ - - - - /** - * Quad Geometric Operations - * ------------------------- - * - * A useful batch of geometric operations used by the quadtree. - */ - - var _geom = { - - /** - * Transforms a graph node with x, y and size into an - * axis-aligned square. - * - * @param {object} A graph node with at least a point (x, y) and a size. - * @return {object} A square: two points (x1, y1), (x2, y2) and height. - */ - pointToSquare: function(n) { - return { - x1: n.x - n.size, - y1: n.y - n.size, - x2: n.x + n.size, - y2: n.y - n.size, - height: n.size * 2 - }; - }, - - /** - * Transforms a graph edge with x1, y1, x2, y2 and size into an - * axis-aligned square. - * - * @param {object} A graph edge with at least two points - * (x1, y1), (x2, y2) and a size. - * @return {object} A square: two points (x1, y1), (x2, y2) and height. - */ - lineToSquare: function(e) { - if (e.y1 < e.y2) { - // (e.x1, e.y1) on top - if (e.x1 < e.x2) { - // (e.x1, e.y1) on left - return { - x1: e.x1 - e.size, - y1: e.y1 - e.size, - x2: e.x2 + e.size, - y2: e.y1 - e.size, - height: e.y2 - e.y1 + e.size * 2 - }; - } - // (e.x1, e.y1) on right - return { - x1: e.x2 - e.size, - y1: e.y1 - e.size, - x2: e.x1 + e.size, - y2: e.y1 - e.size, - height: e.y2 - e.y1 + e.size * 2 - }; - } - - // (e.x2, e.y2) on top - if (e.x1 < e.x2) { - // (e.x1, e.y1) on left - return { - x1: e.x1 - e.size, - y1: e.y2 - e.size, - x2: e.x2 + e.size, - y2: e.y2 - e.size, - height: e.y1 - e.y2 + e.size * 2 - }; - } - // (e.x2, e.y2) on right - return { - x1: e.x2 - e.size, - y1: e.y2 - e.size, - x2: e.x1 + e.size, - y2: e.y2 - e.size, - height: e.y1 - e.y2 + e.size * 2 - }; - }, - - /** - * Transforms a graph edge of type 'curve' with x1, y1, x2, y2, - * control point and size into an axis-aligned square. - * - * @param {object} e A graph edge with at least two points - * (x1, y1), (x2, y2) and a size. - * @param {object} cp A control point (x,y). - * @return {object} A square: two points (x1, y1), (x2, y2) and height. - */ - quadraticCurveToSquare: function(e, cp) { - var pt = sigma.utils.getPointOnQuadraticCurve( - 0.5, - e.x1, - e.y1, - e.x2, - e.y2, - cp.x, - cp.y - ); - - // Bounding box of the two points and the point at the middle of the - // curve: - var minX = Math.min(e.x1, e.x2, pt.x), - maxX = Math.max(e.x1, e.x2, pt.x), - minY = Math.min(e.y1, e.y2, pt.y), - maxY = Math.max(e.y1, e.y2, pt.y); - - return { - x1: minX - e.size, - y1: minY - e.size, - x2: maxX + e.size, - y2: minY - e.size, - height: maxY - minY + e.size * 2 - }; - }, - - /** - * Transforms a graph self loop into an axis-aligned square. - * - * @param {object} n A graph node with a point (x, y) and a size. - * @return {object} A square: two points (x1, y1), (x2, y2) and height. - */ - selfLoopToSquare: function(n) { - // Fitting to the curve is too costly, we compute a larger bounding box - // using the control points: - var cp = sigma.utils.getSelfLoopControlPoints(n.x, n.y, n.size); - - // Bounding box of the point and the two control points: - var minX = Math.min(n.x, cp.x1, cp.x2), - maxX = Math.max(n.x, cp.x1, cp.x2), - minY = Math.min(n.y, cp.y1, cp.y2), - maxY = Math.max(n.y, cp.y1, cp.y2); - - return { - x1: minX - n.size, - y1: minY - n.size, - x2: maxX + n.size, - y2: minY - n.size, - height: maxY - minY + n.size * 2 - }; - }, - - /** - * Checks whether a rectangle is axis-aligned. - * - * @param {object} A rectangle defined by two points - * (x1, y1) and (x2, y2). - * @return {boolean} True if the rectangle is axis-aligned. - */ - isAxisAligned: function(r) { - return r.x1 === r.x2 || r.y1 === r.y2; - }, - - /** - * Compute top points of an axis-aligned rectangle. This is useful in - * cases when the rectangle has been rotated (left, right or bottom up) and - * later operations need to know the top points. - * - * @param {object} An axis-aligned rectangle defined by two points - * (x1, y1), (x2, y2) and height. - * @return {object} A rectangle: two points (x1, y1), (x2, y2) and height. - */ - axisAlignedTopPoints: function(r) { - - // Basic - if (r.y1 === r.y2 && r.x1 < r.x2) - return r; - - // Rotated to right - if (r.x1 === r.x2 && r.y2 > r.y1) - return { - x1: r.x1 - r.height, y1: r.y1, - x2: r.x1, y2: r.y1, - height: r.height - }; - - // Rotated to left - if (r.x1 === r.x2 && r.y2 < r.y1) - return { - x1: r.x1, y1: r.y2, - x2: r.x2 + r.height, y2: r.y2, - height: r.height - }; - - // Bottom's up - return { - x1: r.x2, y1: r.y1 - r.height, - x2: r.x1, y2: r.y1 - r.height, - height: r.height - }; - }, - - /** - * Get coordinates of a rectangle's lower left corner from its top points. - * - * @param {object} A rectangle defined by two points (x1, y1) and (x2, y2). - * @return {object} Coordinates of the corner (x, y). - */ - lowerLeftCoor: function(r) { - var width = ( - Math.sqrt( - Math.pow(r.x2 - r.x1, 2) + - Math.pow(r.y2 - r.y1, 2) - ) - ); - - return { - x: r.x1 - (r.y2 - r.y1) * r.height / width, - y: r.y1 + (r.x2 - r.x1) * r.height / width - }; - }, - - /** - * Get coordinates of a rectangle's lower right corner from its top points - * and its lower left corner. - * - * @param {object} A rectangle defined by two points (x1, y1) and (x2, y2). - * @param {object} A corner's coordinates (x, y). - * @return {object} Coordinates of the corner (x, y). - */ - lowerRightCoor: function(r, llc) { - return { - x: llc.x - r.x1 + r.x2, - y: llc.y - r.y1 + r.y2 - }; - }, - - /** - * Get the coordinates of all the corners of a rectangle from its top point. - * - * @param {object} A rectangle defined by two points (x1, y1) and (x2, y2). - * @return {array} An array of the four corners' coordinates (x, y). - */ - rectangleCorners: function(r) { - var llc = this.lowerLeftCoor(r), - lrc = this.lowerRightCoor(r, llc); - - return [ - {x: r.x1, y: r.y1}, - {x: r.x2, y: r.y2}, - {x: llc.x, y: llc.y}, - {x: lrc.x, y: lrc.y} - ]; - }, - - /** - * Split a square defined by its boundaries into four. - * - * @param {object} Boundaries of the square (x, y, width, height). - * @return {array} An array containing the four new squares, themselves - * defined by an array of their four corners (x, y). - */ - splitSquare: function(b) { - return [ - [ - {x: b.x, y: b.y}, - {x: b.x + b.width / 2, y: b.y}, - {x: b.x, y: b.y + b.height / 2}, - {x: b.x + b.width / 2, y: b.y + b.height / 2} - ], - [ - {x: b.x + b.width / 2, y: b.y}, - {x: b.x + b.width, y: b.y}, - {x: b.x + b.width / 2, y: b.y + b.height / 2}, - {x: b.x + b.width, y: b.y + b.height / 2} - ], - [ - {x: b.x, y: b.y + b.height / 2}, - {x: b.x + b.width / 2, y: b.y + b.height / 2}, - {x: b.x, y: b.y + b.height}, - {x: b.x + b.width / 2, y: b.y + b.height} - ], - [ - {x: b.x + b.width / 2, y: b.y + b.height / 2}, - {x: b.x + b.width, y: b.y + b.height / 2}, - {x: b.x + b.width / 2, y: b.y + b.height}, - {x: b.x + b.width, y: b.y + b.height} - ] - ]; - }, - - /** - * Compute the four axis between corners of rectangle A and corners of - * rectangle B. This is needed later to check an eventual collision. - * - * @param {array} An array of rectangle A's four corners (x, y). - * @param {array} An array of rectangle B's four corners (x, y). - * @return {array} An array of four axis defined by their coordinates (x,y). - */ - axis: function(c1, c2) { - return [ - {x: c1[1].x - c1[0].x, y: c1[1].y - c1[0].y}, - {x: c1[1].x - c1[3].x, y: c1[1].y - c1[3].y}, - {x: c2[0].x - c2[2].x, y: c2[0].y - c2[2].y}, - {x: c2[0].x - c2[1].x, y: c2[0].y - c2[1].y} - ]; - }, - - /** - * Project a rectangle's corner on an axis. - * - * @param {object} Coordinates of a corner (x, y). - * @param {object} Coordinates of an axis (x, y). - * @return {object} The projection defined by coordinates (x, y). - */ - projection: function(c, a) { - var l = ( - (c.x * a.x + c.y * a.y) / - (Math.pow(a.x, 2) + Math.pow(a.y, 2)) - ); - - return { - x: l * a.x, - y: l * a.y - }; - }, - - /** - * Check whether two rectangles collide on one particular axis. - * - * @param {object} An axis' coordinates (x, y). - * @param {array} Rectangle A's corners. - * @param {array} Rectangle B's corners. - * @return {boolean} True if the rectangles collide on the axis. - */ - axisCollision: function(a, c1, c2) { - var sc1 = [], - sc2 = []; - - for (var ci = 0; ci < 4; ci++) { - var p1 = this.projection(c1[ci], a), - p2 = this.projection(c2[ci], a); - - sc1.push(p1.x * a.x + p1.y * a.y); - sc2.push(p2.x * a.x + p2.y * a.y); - } - - var maxc1 = Math.max.apply(Math, sc1), - maxc2 = Math.max.apply(Math, sc2), - minc1 = Math.min.apply(Math, sc1), - minc2 = Math.min.apply(Math, sc2); - - return (minc2 <= maxc1 && maxc2 >= minc1); - }, - - /** - * Check whether two rectangles collide on each one of their four axis. If - * all axis collide, then the two rectangles do collide on the plane. - * - * @param {array} Rectangle A's corners. - * @param {array} Rectangle B's corners. - * @return {boolean} True if the rectangles collide. - */ - collision: function(c1, c2) { - var axis = this.axis(c1, c2), - col = true; - - for (var i = 0; i < 4; i++) - col = col && this.axisCollision(axis[i], c1, c2); - - return col; - } - }; - - - /** - * Quad Functions - * ------------ - * - * The Quadtree functions themselves. - * For each of those functions, we consider that in a splitted quad, the - * index of each node is the following: - * 0: top left - * 1: top right - * 2: bottom left - * 3: bottom right - * - * Moreover, the hereafter quad's philosophy is to consider that if an element - * collides with more than one nodes, this element belongs to each of the - * nodes it collides with where other would let it lie on a higher node. - */ - - /** - * Get the index of the node containing the point in the quad - * - * @param {object} point A point defined by coordinates (x, y). - * @param {object} quadBounds Boundaries of the quad (x, y, width, heigth). - * @return {integer} The index of the node containing the point. - */ - function _quadIndex(point, quadBounds) { - var xmp = quadBounds.x + quadBounds.width / 2, - ymp = quadBounds.y + quadBounds.height / 2, - top = (point.y < ymp), - left = (point.x < xmp); - - if (top) { - if (left) - return 0; - else - return 1; - } - else { - if (left) - return 2; - else - return 3; - } - } - - /** - * Get a list of indexes of nodes containing an axis-aligned rectangle - * - * @param {object} rectangle A rectangle defined by two points (x1, y1), - * (x2, y2) and height. - * @param {array} quadCorners An array of the quad nodes' corners. - * @return {array} An array of indexes containing one to - * four integers. - */ - function _quadIndexes(rectangle, quadCorners) { - var indexes = []; - - // Iterating through quads - for (var i = 0; i < 4; i++) - if ((rectangle.x2 >= quadCorners[i][0].x) && - (rectangle.x1 <= quadCorners[i][1].x) && - (rectangle.y1 + rectangle.height >= quadCorners[i][0].y) && - (rectangle.y1 <= quadCorners[i][2].y)) - indexes.push(i); - - return indexes; - } - - /** - * Get a list of indexes of nodes containing a non-axis-aligned rectangle - * - * @param {array} corners An array containing each corner of the - * rectangle defined by its coordinates (x, y). - * @param {array} quadCorners An array of the quad nodes' corners. - * @return {array} An array of indexes containing one to - * four integers. - */ - function _quadCollision(corners, quadCorners) { - var indexes = []; - - // Iterating through quads - for (var i = 0; i < 4; i++) - if (_geom.collision(corners, quadCorners[i])) - indexes.push(i); - - return indexes; - } - - /** - * Subdivide a quad by creating a node at a precise index. The function does - * not generate all four nodes not to potentially create unused nodes. - * - * @param {integer} index The index of the node to create. - * @param {object} quad The quad object to subdivide. - * @return {object} A new quad representing the node created. - */ - function _quadSubdivide(index, quad) { - var next = quad.level + 1, - subw = Math.round(quad.bounds.width / 2), - subh = Math.round(quad.bounds.height / 2), - qx = Math.round(quad.bounds.x), - qy = Math.round(quad.bounds.y), - x, - y; - - switch (index) { - case 0: - x = qx; - y = qy; - break; - case 1: - x = qx + subw; - y = qy; - break; - case 2: - x = qx; - y = qy + subh; - break; - case 3: - x = qx + subw; - y = qy + subh; - break; - } - - return _quadTree( - {x: x, y: y, width: subw, height: subh}, - next, - quad.maxElements, - quad.maxLevel - ); - } - - /** - * Recursively insert an element into the quadtree. Only points - * with size, i.e. axis-aligned squares, may be inserted with this - * method. - * - * @param {object} el The element to insert in the quadtree. - * @param {object} sizedPoint A sized point defined by two top points - * (x1, y1), (x2, y2) and height. - * @param {object} quad The quad in which to insert the element. - * @return {undefined} The function does not return anything. - */ - function _quadInsert(el, sizedPoint, quad) { - if (quad.level < quad.maxLevel) { - - // Searching appropriate quads - var indexes = _quadIndexes(sizedPoint, quad.corners); - - // Iterating - for (var i = 0, l = indexes.length; i < l; i++) { - - // Subdividing if necessary - if (quad.nodes[indexes[i]] === undefined) - quad.nodes[indexes[i]] = _quadSubdivide(indexes[i], quad); - - // Recursion - _quadInsert(el, sizedPoint, quad.nodes[indexes[i]]); - } - } - else { - - // Pushing the element in a leaf node - quad.elements.push(el); - } - } - - /** - * Recursively retrieve every elements held by the node containing the - * searched point. - * - * @param {object} point The searched point (x, y). - * @param {object} quad The searched quad. - * @return {array} An array of elements contained in the relevant - * node. - */ - function _quadRetrievePoint(point, quad) { - if (quad.level < quad.maxLevel) { - var index = _quadIndex(point, quad.bounds); - - // If node does not exist we return an empty list - if (quad.nodes[index] !== undefined) { - return _quadRetrievePoint(point, quad.nodes[index]); - } - else { - return []; - } - } - else { - return quad.elements; - } - } - - /** - * Recursively retrieve every elements contained within an rectangular area - * that may or may not be axis-aligned. - * - * @param {object|array} rectData The searched area defined either by - * an array of four corners (x, y) in - * the case of a non-axis-aligned - * rectangle or an object with two top - * points (x1, y1), (x2, y2) and height. - * @param {object} quad The searched quad. - * @param {function} collisionFunc The collision function used to search - * for node indexes. - * @param {array?} els The retrieved elements. - * @return {array} An array of elements contained in the - * area. - */ - function _quadRetrieveArea(rectData, quad, collisionFunc, els) { - els = els || {}; - - if (quad.level < quad.maxLevel) { - var indexes = collisionFunc(rectData, quad.corners); - - for (var i = 0, l = indexes.length; i < l; i++) - if (quad.nodes[indexes[i]] !== undefined) - _quadRetrieveArea( - rectData, - quad.nodes[indexes[i]], - collisionFunc, - els - ); - } else - for (var j = 0, m = quad.elements.length; j < m; j++) - if (els[quad.elements[j].id] === undefined) - els[quad.elements[j].id] = quad.elements[j]; - - return els; - } - - /** - * Creates the quadtree object itself. - * - * @param {object} bounds The boundaries of the quad defined by an - * origin (x, y), width and heigth. - * @param {integer} level The level of the quad in the tree. - * @param {integer} maxElements The max number of element in a leaf node. - * @param {integer} maxLevel The max recursion level of the tree. - * @return {object} The quadtree object. - */ - function _quadTree(bounds, level, maxElements, maxLevel) { - return { - level: level || 0, - bounds: bounds, - corners: _geom.splitSquare(bounds), - maxElements: maxElements || 40, - maxLevel: maxLevel || 8, - elements: [], - nodes: [] - }; - } - - - /** - * Sigma Quad Constructor - * ---------------------- - * - * The edgequad API as exposed to sigma. - */ - - /** - * The edgequad core that will become the sigma interface with the quadtree. - * - * property {object} _tree Property holding the quadtree object. - * property {object} _geom Exposition of the _geom namespace for testing. - * property {object} _cache Cache for the area method. - * property {boolean} _enabled Can index and retreive elements. - */ - var edgequad = function() { - this._geom = _geom; - this._tree = null; - this._cache = { - query: false, - result: false - }; - this._enabled = true; - }; - - /** - * Index a graph by inserting its edges into the quadtree. - * - * @param {object} graph A graph instance. - * @param {object} params An object of parameters with at least the quad - * bounds. - * @return {object} The quadtree object. - * - * Parameters: - * ---------- - * bounds: {object} boundaries of the quad defined by its origin (x, y) - * width and heigth. - * prefix: {string?} a prefix for edge geometric attributes. - * maxElements: {integer?} the max number of elements in a leaf node. - * maxLevel: {integer?} the max recursion level of the tree. - */ - edgequad.prototype.index = function(graph, params) { - if (!this._enabled) - return this._tree; - - // Enforcing presence of boundaries - if (!params.bounds) - throw 'sigma.classes.edgequad.index: bounds information not given.'; - - // Prefix - var prefix = params.prefix || '', - cp, - source, - target, - n, - e; - - // Building the tree - this._tree = _quadTree( - params.bounds, - 0, - params.maxElements, - params.maxLevel - ); - - var edges = graph.edges(); - - // Inserting graph edges into the tree - for (var i = 0, l = edges.length; i < l; i++) { - source = graph.nodes(edges[i].source); - target = graph.nodes(edges[i].target); - e = { - x1: source[prefix + 'x'], - y1: source[prefix + 'y'], - x2: target[prefix + 'x'], - y2: target[prefix + 'y'], - size: edges[i][prefix + 'size'] || 0 - }; - - // Inserting edge - if (edges[i].type === 'curve' || edges[i].type === 'curvedArrow') { - if (source.id === target.id) { - n = { - x: source[prefix + 'x'], - y: source[prefix + 'y'], - size: source[prefix + 'size'] || 0 - }; - _quadInsert( - edges[i], - _geom.selfLoopToSquare(n), - this._tree); - } - else { - cp = sigma.utils.getQuadraticControlPoint(e.x1, e.y1, e.x2, e.y2); - _quadInsert( - edges[i], - _geom.quadraticCurveToSquare(e, cp), - this._tree); - } - } - else { - _quadInsert( - edges[i], - _geom.lineToSquare(e), - this._tree); - } - } - - // Reset cache: - this._cache = { - query: false, - result: false - }; - - // remove? - return this._tree; - }; - - /** - * Retrieve every graph edges held by the quadtree node containing the - * searched point. - * - * @param {number} x of the point. - * @param {number} y of the point. - * @return {array} An array of edges retrieved. - */ - edgequad.prototype.point = function(x, y) { - if (!this._enabled) - return []; - - return this._tree ? - _quadRetrievePoint({x: x, y: y}, this._tree) || [] : - []; - }; - - /** - * Retrieve every graph edges within a rectangular area. The methods keep the - * last area queried in cache for optimization reason and will act differently - * for the same reason if the area is axis-aligned or not. - * - * @param {object} A rectangle defined by two top points (x1, y1), (x2, y2) - * and height. - * @return {array} An array of edges retrieved. - */ - edgequad.prototype.area = function(rect) { - if (!this._enabled) - return []; - - var serialized = JSON.stringify(rect), - collisionFunc, - rectData; - - // Returning cache? - if (this._cache.query === serialized) - return this._cache.result; - - // Axis aligned ? - if (_geom.isAxisAligned(rect)) { - collisionFunc = _quadIndexes; - rectData = _geom.axisAlignedTopPoints(rect); - } - else { - collisionFunc = _quadCollision; - rectData = _geom.rectangleCorners(rect); - } - - // Retrieving edges - var edges = this._tree ? - _quadRetrieveArea( - rectData, - this._tree, - collisionFunc - ) : - []; - - // Object to array - var edgesArray = []; - for (var i in edges) - edgesArray.push(edges[i]); - - // Caching - this._cache.query = serialized; - this._cache.result = edgesArray; - - return edgesArray; - }; - - - /** - * EXPORT: - * ******* - */ - if (typeof this.sigma !== 'undefined') { - this.sigma.classes = this.sigma.classes || {}; - this.sigma.classes.edgequad = edgequad; - } else if (typeof exports !== 'undefined') { - if (typeof module !== 'undefined' && module.exports) - exports = module.exports = edgequad; - exports.edgequad = edgequad; - } else - this.edgequad = edgequad; -}).call(this); diff --git a/src/demo/static/sigmajs/classes/sigma.classes.graph.js b/src/demo/static/sigmajs/classes/sigma.classes.graph.js deleted file mode 100644 index c7ebe9dd4..000000000 --- a/src/demo/static/sigmajs/classes/sigma.classes.graph.js +++ /dev/null @@ -1,859 +0,0 @@ -;(function(undefined) { - 'use strict'; - - var _methods = Object.create(null), - _indexes = Object.create(null), - _initBindings = Object.create(null), - _methodBindings = Object.create(null), - _methodBeforeBindings = Object.create(null), - _defaultSettings = { - immutable: true, - clone: true - }, - _defaultSettingsFunction = function(key) { - return _defaultSettings[key]; - }; - - /** - * The graph constructor. It initializes the data and the indexes, and binds - * the custom indexes and methods to its own scope. - * - * Recognized parameters: - * ********************** - * Here is the exhaustive list of every accepted parameters in the settings - * object: - * - * {boolean} clone Indicates if the data have to be cloned in methods - * to add nodes or edges. - * {boolean} immutable Indicates if nodes "id" values and edges "id", - * "source" and "target" values must be set as - * immutable. - * - * @param {?configurable} settings Eventually a settings function. - * @return {graph} The new graph instance. - */ - var graph = function(settings) { - var k, - fn, - data; - - /** - * DATA: - * ***** - * Every data that is callable from graph methods are stored in this "data" - * object. This object will be served as context for all these methods, - * and it is possible to add other type of data in it. - */ - data = { - /** - * SETTINGS FUNCTION: - * ****************** - */ - settings: settings || _defaultSettingsFunction, - - /** - * MAIN DATA: - * ********** - */ - nodesArray: [], - edgesArray: [], - - /** - * GLOBAL INDEXES: - * *************** - * These indexes just index data by ids. - */ - nodesIndex: Object.create(null), - edgesIndex: Object.create(null), - - /** - * LOCAL INDEXES: - * ************** - * These indexes refer from node to nodes. Each key is an id, and each - * value is the array of the ids of related nodes. - */ - inNeighborsIndex: Object.create(null), - outNeighborsIndex: Object.create(null), - allNeighborsIndex: Object.create(null), - - inNeighborsCount: Object.create(null), - outNeighborsCount: Object.create(null), - allNeighborsCount: Object.create(null) - }; - - // Execute bindings: - for (k in _initBindings) - _initBindings[k].call(data); - - // Add methods to both the scope and the data objects: - for (k in _methods) { - fn = __bindGraphMethod(k, data, _methods[k]); - this[k] = fn; - data[k] = fn; - } - }; - - - - - /** - * A custom tool to bind methods such that function that are bound to it will - * be executed anytime the method is called. - * - * @param {string} methodName The name of the method to bind. - * @param {object} scope The scope where the method must be executed. - * @param {function} fn The method itself. - * @return {function} The new method. - */ - function __bindGraphMethod(methodName, scope, fn) { - var result = function() { - var k, - res; - - // Execute "before" bound functions: - for (k in _methodBeforeBindings[methodName]) - _methodBeforeBindings[methodName][k].apply(scope, arguments); - - // Apply the method: - res = fn.apply(scope, arguments); - - // Execute bound functions: - for (k in _methodBindings[methodName]) - _methodBindings[methodName][k].apply(scope, arguments); - - // Return res: - return res; - }; - - return result; - } - - /** - * This custom tool function removes every pair key/value from an hash. The - * goal is to avoid creating a new object while some other references are - * still hanging in some scopes... - * - * @param {object} obj The object to empty. - * @return {object} The empty object. - */ - function __emptyObject(obj) { - var k; - - for (k in obj) - if (!('hasOwnProperty' in obj) || obj.hasOwnProperty(k)) - delete obj[k]; - - return obj; - } - - - - - /** - * This global method adds a method that will be bound to the futurly created - * graph instances. - * - * Since these methods will be bound to their scope when the instances are - * created, it does not use the prototype. Because of that, methods have to - * be added before instances are created to make them available. - * - * Here is an example: - * - * > graph.addMethod('getNodesCount', function() { - * > return this.nodesArray.length; - * > }); - * > - * > var myGraph = new graph(); - * > console.log(myGraph.getNodesCount()); // outputs 0 - * - * @param {string} methodName The name of the method. - * @param {function} fn The method itself. - * @return {object} The global graph constructor. - */ - graph.addMethod = function(methodName, fn) { - if ( - typeof methodName !== 'string' || - typeof fn !== 'function' || - arguments.length !== 2 - ) - throw 'addMethod: Wrong arguments.'; - - if (_methods[methodName] || graph[methodName]) - throw 'The method "' + methodName + '" already exists.'; - - _methods[methodName] = fn; - _methodBindings[methodName] = Object.create(null); - _methodBeforeBindings[methodName] = Object.create(null); - - return this; - }; - - /** - * This global method returns true if the method has already been added, and - * false else. - * - * Here are some examples: - * - * > graph.hasMethod('addNode'); // returns true - * > graph.hasMethod('hasMethod'); // returns true - * > graph.hasMethod('unexistingMethod'); // returns false - * - * @param {string} methodName The name of the method. - * @return {boolean} The result. - */ - graph.hasMethod = function(methodName) { - return !!(_methods[methodName] || graph[methodName]); - }; - - /** - * This global methods attaches a function to a method. Anytime the specified - * method is called, the attached function is called right after, with the - * same arguments and in the same scope. The attached function is called - * right before if the last argument is true, unless the method is the graph - * constructor. - * - * To attach a function to the graph constructor, use 'constructor' as the - * method name (first argument). - * - * The main idea is to have a clean way to keep custom indexes up to date, - * for instance: - * - * > var timesAddNodeCalled = 0; - * > graph.attach('addNode', 'timesAddNodeCalledInc', function() { - * > timesAddNodeCalled++; - * > }); - * > - * > var myGraph = new graph(); - * > console.log(timesAddNodeCalled); // outputs 0 - * > - * > myGraph.addNode({ id: '1' }).addNode({ id: '2' }); - * > console.log(timesAddNodeCalled); // outputs 2 - * - * The idea for calling a function before is to provide pre-processors, for - * instance: - * - * > var colorPalette = { Person: '#C3CBE1', Place: '#9BDEBD' }; - * > graph.attach('addNode', 'applyNodeColorPalette', function(n) { - * > n.color = colorPalette[n.category]; - * > }, true); - * > - * > var myGraph = new graph(); - * > myGraph.addNode({ id: 'n0', category: 'Person' }); - * > console.log(myGraph.nodes('n0').color); // outputs '#C3CBE1' - * - * @param {string} methodName The name of the related method or - * "constructor". - * @param {string} key The key to identify the function to attach. - * @param {function} fn The function to bind. - * @param {boolean} before If true the function is called right before. - * @return {object} The global graph constructor. - */ - graph.attach = function(methodName, key, fn, before) { - if ( - typeof methodName !== 'string' || - typeof key !== 'string' || - typeof fn !== 'function' || - arguments.length < 3 || - arguments.length > 4 - ) - throw 'attach: Wrong arguments.'; - - var bindings; - - if (methodName === 'constructor') - bindings = _initBindings; - else { - if (before) { - if (!_methodBeforeBindings[methodName]) - throw 'The method "' + methodName + '" does not exist.'; - - bindings = _methodBeforeBindings[methodName]; - } - else { - if (!_methodBindings[methodName]) - throw 'The method "' + methodName + '" does not exist.'; - - bindings = _methodBindings[methodName]; - } - } - - if (bindings[key]) - throw 'A function "' + key + '" is already attached ' + - 'to the method "' + methodName + '".'; - - bindings[key] = fn; - - return this; - }; - - /** - * Alias of attach(methodName, key, fn, true). - */ - graph.attachBefore = function(methodName, key, fn) { - return this.attach(methodName, key, fn, true); - }; - - /** - * This methods is just an helper to deal with custom indexes. It takes as - * arguments the name of the index and an object containing all the different - * functions to bind to the methods. - * - * Here is a basic example, that creates an index to keep the number of nodes - * in the current graph. It also adds a method to provide a getter on that - * new index: - * - * > sigma.classes.graph.addIndex('nodesCount', { - * > constructor: function() { - * > this.nodesCount = 0; - * > }, - * > addNode: function() { - * > this.nodesCount++; - * > }, - * > dropNode: function() { - * > this.nodesCount--; - * > } - * > }); - * > - * > sigma.classes.graph.addMethod('getNodesCount', function() { - * > return this.nodesCount; - * > }); - * > - * > var myGraph = new sigma.classes.graph(); - * > console.log(myGraph.getNodesCount()); // outputs 0 - * > - * > myGraph.addNode({ id: '1' }).addNode({ id: '2' }); - * > console.log(myGraph.getNodesCount()); // outputs 2 - * - * @param {string} name The name of the index. - * @param {object} bindings The object containing the functions to bind. - * @return {object} The global graph constructor. - */ - graph.addIndex = function(name, bindings) { - if ( - typeof name !== 'string' || - Object(bindings) !== bindings || - arguments.length !== 2 - ) - throw 'addIndex: Wrong arguments.'; - - if (_indexes[name]) - throw 'The index "' + name + '" already exists.'; - - var k; - - // Store the bindings: - _indexes[name] = bindings; - - // Attach the bindings: - for (k in bindings) - if (typeof bindings[k] !== 'function') - throw 'The bindings must be functions.'; - else - graph.attach(k, name, bindings[k]); - - return this; - }; - - - - - /** - * This method adds a node to the graph. The node must be an object, with a - * string under the key "id". Except for this, it is possible to add any - * other attribute, that will be preserved all along the manipulations. - * - * If the graph option "clone" has a truthy value, the node will be cloned - * when added to the graph. Also, if the graph option "immutable" has a - * truthy value, its id will be defined as immutable. - * - * @param {object} node The node to add. - * @return {object} The graph instance. - */ - graph.addMethod('addNode', function(node) { - // Check that the node is an object and has an id: - if (Object(node) !== node || arguments.length !== 1) - throw 'addNode: Wrong arguments.'; - - if (typeof node.id !== 'string' && typeof node.id !== 'number') - throw 'The node must have a string or number id.'; - - if (this.nodesIndex[node.id]) - throw 'The node "' + node.id + '" already exists.'; - - var k, - id = node.id, - validNode = Object.create(null); - - // Check the "clone" option: - if (this.settings('clone')) { - for (k in node) - if (k !== 'id') - validNode[k] = node[k]; - } else - validNode = node; - - // Check the "immutable" option: - if (this.settings('immutable')) - Object.defineProperty(validNode, 'id', { - value: id, - enumerable: true - }); - else - validNode.id = id; - - // Add empty containers for edges indexes: - this.inNeighborsIndex[id] = Object.create(null); - this.outNeighborsIndex[id] = Object.create(null); - this.allNeighborsIndex[id] = Object.create(null); - - this.inNeighborsCount[id] = 0; - this.outNeighborsCount[id] = 0; - this.allNeighborsCount[id] = 0; - - // Add the node to indexes: - this.nodesArray.push(validNode); - this.nodesIndex[validNode.id] = validNode; - - // Return the current instance: - return this; - }); - - /** - * This method adds an edge to the graph. The edge must be an object, with a - * string under the key "id", and strings under the keys "source" and - * "target" that design existing nodes. Except for this, it is possible to - * add any other attribute, that will be preserved all along the - * manipulations. - * - * If the graph option "clone" has a truthy value, the edge will be cloned - * when added to the graph. Also, if the graph option "immutable" has a - * truthy value, its id, source and target will be defined as immutable. - * - * @param {object} edge The edge to add. - * @return {object} The graph instance. - */ - graph.addMethod('addEdge', function(edge) { - // Check that the edge is an object and has an id: - if (Object(edge) !== edge || arguments.length !== 1) - throw 'addEdge: Wrong arguments.'; - - if (typeof edge.id !== 'string' && typeof edge.id !== 'number') - throw 'The edge must have a string or number id.'; - - if ((typeof edge.source !== 'string' && typeof edge.source !== 'number') || - !this.nodesIndex[edge.source]) - throw 'The edge source must have an existing node id.'; - - if ((typeof edge.target !== 'string' && typeof edge.target !== 'number') || - !this.nodesIndex[edge.target]) - throw 'The edge target must have an existing node id.'; - - if (this.edgesIndex[edge.id]) - throw 'The edge "' + edge.id + '" already exists.'; - - var k, - validEdge = Object.create(null); - - // Check the "clone" option: - if (this.settings('clone')) { - for (k in edge) - if (k !== 'id' && k !== 'source' && k !== 'target') - validEdge[k] = edge[k]; - } else - validEdge = edge; - - // Check the "immutable" option: - if (this.settings('immutable')) { - Object.defineProperty(validEdge, 'id', { - value: edge.id, - enumerable: true - }); - - Object.defineProperty(validEdge, 'source', { - value: edge.source, - enumerable: true - }); - - Object.defineProperty(validEdge, 'target', { - value: edge.target, - enumerable: true - }); - } else { - validEdge.id = edge.id; - validEdge.source = edge.source; - validEdge.target = edge.target; - } - - // Add the edge to indexes: - this.edgesArray.push(validEdge); - this.edgesIndex[validEdge.id] = validEdge; - - if (!this.inNeighborsIndex[validEdge.target][validEdge.source]) - this.inNeighborsIndex[validEdge.target][validEdge.source] = - Object.create(null); - this.inNeighborsIndex[validEdge.target][validEdge.source][validEdge.id] = - validEdge; - - if (!this.outNeighborsIndex[validEdge.source][validEdge.target]) - this.outNeighborsIndex[validEdge.source][validEdge.target] = - Object.create(null); - this.outNeighborsIndex[validEdge.source][validEdge.target][validEdge.id] = - validEdge; - - if (!this.allNeighborsIndex[validEdge.source][validEdge.target]) - this.allNeighborsIndex[validEdge.source][validEdge.target] = - Object.create(null); - this.allNeighborsIndex[validEdge.source][validEdge.target][validEdge.id] = - validEdge; - - if (validEdge.target !== validEdge.source) { - if (!this.allNeighborsIndex[validEdge.target][validEdge.source]) - this.allNeighborsIndex[validEdge.target][validEdge.source] = - Object.create(null); - this.allNeighborsIndex[validEdge.target][validEdge.source][validEdge.id] = - validEdge; - } - - // Keep counts up to date: - this.inNeighborsCount[validEdge.target]++; - this.outNeighborsCount[validEdge.source]++; - this.allNeighborsCount[validEdge.target]++; - this.allNeighborsCount[validEdge.source]++; - - return this; - }); - - /** - * This method drops a node from the graph. It also removes each edge that is - * bound to it, through the dropEdge method. An error is thrown if the node - * does not exist. - * - * @param {string} id The node id. - * @return {object} The graph instance. - */ - graph.addMethod('dropNode', function(id) { - // Check that the arguments are valid: - if ((typeof id !== 'string' && typeof id !== 'number') || - arguments.length !== 1) - throw 'dropNode: Wrong arguments.'; - - if (!this.nodesIndex[id]) - throw 'The node "' + id + '" does not exist.'; - - var i, k, l; - - // Remove the node from indexes: - delete this.nodesIndex[id]; - for (i = 0, l = this.nodesArray.length; i < l; i++) - if (this.nodesArray[i].id === id) { - this.nodesArray.splice(i, 1); - break; - } - - // Remove related edges: - for (i = this.edgesArray.length - 1; i >= 0; i--) - if (this.edgesArray[i].source === id || this.edgesArray[i].target === id) - this.dropEdge(this.edgesArray[i].id); - - // Remove related edge indexes: - delete this.inNeighborsIndex[id]; - delete this.outNeighborsIndex[id]; - delete this.allNeighborsIndex[id]; - - delete this.inNeighborsCount[id]; - delete this.outNeighborsCount[id]; - delete this.allNeighborsCount[id]; - - for (k in this.nodesIndex) { - delete this.inNeighborsIndex[k][id]; - delete this.outNeighborsIndex[k][id]; - delete this.allNeighborsIndex[k][id]; - } - - return this; - }); - - /** - * This method drops an edge from the graph. An error is thrown if the edge - * does not exist. - * - * @param {string} id The edge id. - * @return {object} The graph instance. - */ - graph.addMethod('dropEdge', function(id) { - // Check that the arguments are valid: - if ((typeof id !== 'string' && typeof id !== 'number') || - arguments.length !== 1) - throw 'dropEdge: Wrong arguments.'; - - if (!this.edgesIndex[id]) - throw 'The edge "' + id + '" does not exist.'; - - var i, l, edge; - - // Remove the edge from indexes: - edge = this.edgesIndex[id]; - delete this.edgesIndex[id]; - for (i = 0, l = this.edgesArray.length; i < l; i++) - if (this.edgesArray[i].id === id) { - this.edgesArray.splice(i, 1); - break; - } - - delete this.inNeighborsIndex[edge.target][edge.source][edge.id]; - if (!Object.keys(this.inNeighborsIndex[edge.target][edge.source]).length) - delete this.inNeighborsIndex[edge.target][edge.source]; - - delete this.outNeighborsIndex[edge.source][edge.target][edge.id]; - if (!Object.keys(this.outNeighborsIndex[edge.source][edge.target]).length) - delete this.outNeighborsIndex[edge.source][edge.target]; - - delete this.allNeighborsIndex[edge.source][edge.target][edge.id]; - if (!Object.keys(this.allNeighborsIndex[edge.source][edge.target]).length) - delete this.allNeighborsIndex[edge.source][edge.target]; - - if (edge.target !== edge.source) { - delete this.allNeighborsIndex[edge.target][edge.source][edge.id]; - if (!Object.keys(this.allNeighborsIndex[edge.target][edge.source]).length) - delete this.allNeighborsIndex[edge.target][edge.source]; - } - - this.inNeighborsCount[edge.target]--; - this.outNeighborsCount[edge.source]--; - this.allNeighborsCount[edge.source]--; - this.allNeighborsCount[edge.target]--; - - return this; - }); - - /** - * This method destroys the current instance. It basically empties each index - * and methods attached to the graph. - */ - graph.addMethod('kill', function() { - // Delete arrays: - this.nodesArray.length = 0; - this.edgesArray.length = 0; - delete this.nodesArray; - delete this.edgesArray; - - // Delete indexes: - delete this.nodesIndex; - delete this.edgesIndex; - delete this.inNeighborsIndex; - delete this.outNeighborsIndex; - delete this.allNeighborsIndex; - delete this.inNeighborsCount; - delete this.outNeighborsCount; - delete this.allNeighborsCount; - }); - - /** - * This method empties the nodes and edges arrays, as well as the different - * indexes. - * - * @return {object} The graph instance. - */ - graph.addMethod('clear', function() { - this.nodesArray.length = 0; - this.edgesArray.length = 0; - - // Due to GC issues, I prefer not to create new object. These objects are - // only available from the methods and attached functions, but still, it is - // better to prevent ghost references to unrelevant data... - __emptyObject(this.nodesIndex); - __emptyObject(this.edgesIndex); - __emptyObject(this.nodesIndex); - __emptyObject(this.inNeighborsIndex); - __emptyObject(this.outNeighborsIndex); - __emptyObject(this.allNeighborsIndex); - __emptyObject(this.inNeighborsCount); - __emptyObject(this.outNeighborsCount); - __emptyObject(this.allNeighborsCount); - - return this; - }); - - /** - * This method reads an object and adds the nodes and edges, through the - * proper methods "addNode" and "addEdge". - * - * Here is an example: - * - * > var myGraph = new graph(); - * > myGraph.read({ - * > nodes: [ - * > { id: 'n0' }, - * > { id: 'n1' } - * > ], - * > edges: [ - * > { - * > id: 'e0', - * > source: 'n0', - * > target: 'n1' - * > } - * > ] - * > }); - * > - * > console.log( - * > myGraph.nodes().length, - * > myGraph.edges().length - * > ); // outputs 2 1 - * - * @param {object} g The graph object. - * @return {object} The graph instance. - */ - graph.addMethod('read', function(g) { - var i, - a, - l; - - a = g.nodes || []; - for (i = 0, l = a.length; i < l; i++) - this.addNode(a[i]); - - a = g.edges || []; - for (i = 0, l = a.length; i < l; i++) - this.addEdge(a[i]); - - return this; - }); - - /** - * This methods returns one or several nodes, depending on how it is called. - * - * To get the array of nodes, call "nodes" without argument. To get a - * specific node, call it with the id of the node. The get multiple node, - * call it with an array of ids, and it will return the array of nodes, in - * the same order. - * - * @param {?(string|array)} v Eventually one id, an array of ids. - * @return {object|array} The related node or array of nodes. - */ - graph.addMethod('nodes', function(v) { - // Clone the array of nodes and return it: - if (!arguments.length) - return this.nodesArray.slice(0); - - // Return the related node: - if (arguments.length === 1 && - (typeof v === 'string' || typeof v === 'number')) - return this.nodesIndex[v]; - - // Return an array of the related node: - if ( - arguments.length === 1 && - Object.prototype.toString.call(v) === '[object Array]' - ) { - var i, - l, - a = []; - - for (i = 0, l = v.length; i < l; i++) - if (typeof v[i] === 'string' || typeof v[i] === 'number') - a.push(this.nodesIndex[v[i]]); - else - throw 'nodes: Wrong arguments.'; - - return a; - } - - throw 'nodes: Wrong arguments.'; - }); - - /** - * This methods returns the degree of one or several nodes, depending on how - * it is called. It is also possible to get incoming or outcoming degrees - * instead by specifying 'in' or 'out' as a second argument. - * - * @param {string|array} v One id, an array of ids. - * @param {?string} which Which degree is required. Values are 'in', - * 'out', and by default the normal degree. - * @return {number|array} The related degree or array of degrees. - */ - graph.addMethod('degree', function(v, which) { - // Check which degree is required: - which = { - 'in': this.inNeighborsCount, - 'out': this.outNeighborsCount - }[which || ''] || this.allNeighborsCount; - - // Return the related node: - if (typeof v === 'string' || typeof v === 'number') - return which[v]; - - // Return an array of the related node: - if (Object.prototype.toString.call(v) === '[object Array]') { - var i, - l, - a = []; - - for (i = 0, l = v.length; i < l; i++) - if (typeof v[i] === 'string' || typeof v[i] === 'number') - a.push(which[v[i]]); - else - throw 'degree: Wrong arguments.'; - - return a; - } - - throw 'degree: Wrong arguments.'; - }); - - /** - * This methods returns one or several edges, depending on how it is called. - * - * To get the array of edges, call "edges" without argument. To get a - * specific edge, call it with the id of the edge. The get multiple edge, - * call it with an array of ids, and it will return the array of edges, in - * the same order. - * - * @param {?(string|array)} v Eventually one id, an array of ids. - * @return {object|array} The related edge or array of edges. - */ - graph.addMethod('edges', function(v) { - // Clone the array of edges and return it: - if (!arguments.length) - return this.edgesArray.slice(0); - - // Return the related edge: - if (arguments.length === 1 && - (typeof v === 'string' || typeof v === 'number')) - return this.edgesIndex[v]; - - // Return an array of the related edge: - if ( - arguments.length === 1 && - Object.prototype.toString.call(v) === '[object Array]' - ) { - var i, - l, - a = []; - - for (i = 0, l = v.length; i < l; i++) - if (typeof v[i] === 'string' || typeof v[i] === 'number') - a.push(this.edgesIndex[v[i]]); - else - throw 'edges: Wrong arguments.'; - - return a; - } - - throw 'edges: Wrong arguments.'; - }); - - - /** - * EXPORT: - * ******* - */ - if (typeof sigma !== 'undefined') { - sigma.classes = sigma.classes || Object.create(null); - sigma.classes.graph = graph; - } else if (typeof exports !== 'undefined') { - if (typeof module !== 'undefined' && module.exports) - exports = module.exports = graph; - exports.graph = graph; - } else - this.graph = graph; -}).call(this); diff --git a/src/demo/static/sigmajs/classes/sigma.classes.quad.js b/src/demo/static/sigmajs/classes/sigma.classes.quad.js deleted file mode 100644 index fb1138636..000000000 --- a/src/demo/static/sigmajs/classes/sigma.classes.quad.js +++ /dev/null @@ -1,674 +0,0 @@ -;(function(undefined) { - 'use strict'; - - /** - * Sigma Quadtree Module - * ===================== - * - * Author: Guillaume Plique (Yomguithereal) - * Version: 0.2 - */ - - - - /** - * Quad Geometric Operations - * ------------------------- - * - * A useful batch of geometric operations used by the quadtree. - */ - - var _geom = { - - /** - * Transforms a graph node with x, y and size into an - * axis-aligned square. - * - * @param {object} A graph node with at least a point (x, y) and a size. - * @return {object} A square: two points (x1, y1), (x2, y2) and height. - */ - pointToSquare: function(n) { - return { - x1: n.x - n.size, - y1: n.y - n.size, - x2: n.x + n.size, - y2: n.y - n.size, - height: n.size * 2 - }; - }, - - /** - * Checks whether a rectangle is axis-aligned. - * - * @param {object} A rectangle defined by two points - * (x1, y1) and (x2, y2). - * @return {boolean} True if the rectangle is axis-aligned. - */ - isAxisAligned: function(r) { - return r.x1 === r.x2 || r.y1 === r.y2; - }, - - /** - * Compute top points of an axis-aligned rectangle. This is useful in - * cases when the rectangle has been rotated (left, right or bottom up) and - * later operations need to know the top points. - * - * @param {object} An axis-aligned rectangle defined by two points - * (x1, y1), (x2, y2) and height. - * @return {object} A rectangle: two points (x1, y1), (x2, y2) and height. - */ - axisAlignedTopPoints: function(r) { - - // Basic - if (r.y1 === r.y2 && r.x1 < r.x2) - return r; - - // Rotated to right - if (r.x1 === r.x2 && r.y2 > r.y1) - return { - x1: r.x1 - r.height, y1: r.y1, - x2: r.x1, y2: r.y1, - height: r.height - }; - - // Rotated to left - if (r.x1 === r.x2 && r.y2 < r.y1) - return { - x1: r.x1, y1: r.y2, - x2: r.x2 + r.height, y2: r.y2, - height: r.height - }; - - // Bottom's up - return { - x1: r.x2, y1: r.y1 - r.height, - x2: r.x1, y2: r.y1 - r.height, - height: r.height - }; - }, - - /** - * Get coordinates of a rectangle's lower left corner from its top points. - * - * @param {object} A rectangle defined by two points (x1, y1) and (x2, y2). - * @return {object} Coordinates of the corner (x, y). - */ - lowerLeftCoor: function(r) { - var width = ( - Math.sqrt( - Math.pow(r.x2 - r.x1, 2) + - Math.pow(r.y2 - r.y1, 2) - ) - ); - - return { - x: r.x1 - (r.y2 - r.y1) * r.height / width, - y: r.y1 + (r.x2 - r.x1) * r.height / width - }; - }, - - /** - * Get coordinates of a rectangle's lower right corner from its top points - * and its lower left corner. - * - * @param {object} A rectangle defined by two points (x1, y1) and (x2, y2). - * @param {object} A corner's coordinates (x, y). - * @return {object} Coordinates of the corner (x, y). - */ - lowerRightCoor: function(r, llc) { - return { - x: llc.x - r.x1 + r.x2, - y: llc.y - r.y1 + r.y2 - }; - }, - - /** - * Get the coordinates of all the corners of a rectangle from its top point. - * - * @param {object} A rectangle defined by two points (x1, y1) and (x2, y2). - * @return {array} An array of the four corners' coordinates (x, y). - */ - rectangleCorners: function(r) { - var llc = this.lowerLeftCoor(r), - lrc = this.lowerRightCoor(r, llc); - - return [ - {x: r.x1, y: r.y1}, - {x: r.x2, y: r.y2}, - {x: llc.x, y: llc.y}, - {x: lrc.x, y: lrc.y} - ]; - }, - - /** - * Split a square defined by its boundaries into four. - * - * @param {object} Boundaries of the square (x, y, width, height). - * @return {array} An array containing the four new squares, themselves - * defined by an array of their four corners (x, y). - */ - splitSquare: function(b) { - return [ - [ - {x: b.x, y: b.y}, - {x: b.x + b.width / 2, y: b.y}, - {x: b.x, y: b.y + b.height / 2}, - {x: b.x + b.width / 2, y: b.y + b.height / 2} - ], - [ - {x: b.x + b.width / 2, y: b.y}, - {x: b.x + b.width, y: b.y}, - {x: b.x + b.width / 2, y: b.y + b.height / 2}, - {x: b.x + b.width, y: b.y + b.height / 2} - ], - [ - {x: b.x, y: b.y + b.height / 2}, - {x: b.x + b.width / 2, y: b.y + b.height / 2}, - {x: b.x, y: b.y + b.height}, - {x: b.x + b.width / 2, y: b.y + b.height} - ], - [ - {x: b.x + b.width / 2, y: b.y + b.height / 2}, - {x: b.x + b.width, y: b.y + b.height / 2}, - {x: b.x + b.width / 2, y: b.y + b.height}, - {x: b.x + b.width, y: b.y + b.height} - ] - ]; - }, - - /** - * Compute the four axis between corners of rectangle A and corners of - * rectangle B. This is needed later to check an eventual collision. - * - * @param {array} An array of rectangle A's four corners (x, y). - * @param {array} An array of rectangle B's four corners (x, y). - * @return {array} An array of four axis defined by their coordinates (x,y). - */ - axis: function(c1, c2) { - return [ - {x: c1[1].x - c1[0].x, y: c1[1].y - c1[0].y}, - {x: c1[1].x - c1[3].x, y: c1[1].y - c1[3].y}, - {x: c2[0].x - c2[2].x, y: c2[0].y - c2[2].y}, - {x: c2[0].x - c2[1].x, y: c2[0].y - c2[1].y} - ]; - }, - - /** - * Project a rectangle's corner on an axis. - * - * @param {object} Coordinates of a corner (x, y). - * @param {object} Coordinates of an axis (x, y). - * @return {object} The projection defined by coordinates (x, y). - */ - projection: function(c, a) { - var l = ( - (c.x * a.x + c.y * a.y) / - (Math.pow(a.x, 2) + Math.pow(a.y, 2)) - ); - - return { - x: l * a.x, - y: l * a.y - }; - }, - - /** - * Check whether two rectangles collide on one particular axis. - * - * @param {object} An axis' coordinates (x, y). - * @param {array} Rectangle A's corners. - * @param {array} Rectangle B's corners. - * @return {boolean} True if the rectangles collide on the axis. - */ - axisCollision: function(a, c1, c2) { - var sc1 = [], - sc2 = []; - - for (var ci = 0; ci < 4; ci++) { - var p1 = this.projection(c1[ci], a), - p2 = this.projection(c2[ci], a); - - sc1.push(p1.x * a.x + p1.y * a.y); - sc2.push(p2.x * a.x + p2.y * a.y); - } - - var maxc1 = Math.max.apply(Math, sc1), - maxc2 = Math.max.apply(Math, sc2), - minc1 = Math.min.apply(Math, sc1), - minc2 = Math.min.apply(Math, sc2); - - return (minc2 <= maxc1 && maxc2 >= minc1); - }, - - /** - * Check whether two rectangles collide on each one of their four axis. If - * all axis collide, then the two rectangles do collide on the plane. - * - * @param {array} Rectangle A's corners. - * @param {array} Rectangle B's corners. - * @return {boolean} True if the rectangles collide. - */ - collision: function(c1, c2) { - var axis = this.axis(c1, c2), - col = true; - - for (var i = 0; i < 4; i++) - col = col && this.axisCollision(axis[i], c1, c2); - - return col; - } - }; - - - /** - * Quad Functions - * ------------ - * - * The Quadtree functions themselves. - * For each of those functions, we consider that in a splitted quad, the - * index of each node is the following: - * 0: top left - * 1: top right - * 2: bottom left - * 3: bottom right - * - * Moreover, the hereafter quad's philosophy is to consider that if an element - * collides with more than one nodes, this element belongs to each of the - * nodes it collides with where other would let it lie on a higher node. - */ - - /** - * Get the index of the node containing the point in the quad - * - * @param {object} point A point defined by coordinates (x, y). - * @param {object} quadBounds Boundaries of the quad (x, y, width, heigth). - * @return {integer} The index of the node containing the point. - */ - function _quadIndex(point, quadBounds) { - var xmp = quadBounds.x + quadBounds.width / 2, - ymp = quadBounds.y + quadBounds.height / 2, - top = (point.y < ymp), - left = (point.x < xmp); - - if (top) { - if (left) - return 0; - else - return 1; - } - else { - if (left) - return 2; - else - return 3; - } - } - - /** - * Get a list of indexes of nodes containing an axis-aligned rectangle - * - * @param {object} rectangle A rectangle defined by two points (x1, y1), - * (x2, y2) and height. - * @param {array} quadCorners An array of the quad nodes' corners. - * @return {array} An array of indexes containing one to - * four integers. - */ - function _quadIndexes(rectangle, quadCorners) { - var indexes = []; - - // Iterating through quads - for (var i = 0; i < 4; i++) - if ((rectangle.x2 >= quadCorners[i][0].x) && - (rectangle.x1 <= quadCorners[i][1].x) && - (rectangle.y1 + rectangle.height >= quadCorners[i][0].y) && - (rectangle.y1 <= quadCorners[i][2].y)) - indexes.push(i); - - return indexes; - } - - /** - * Get a list of indexes of nodes containing a non-axis-aligned rectangle - * - * @param {array} corners An array containing each corner of the - * rectangle defined by its coordinates (x, y). - * @param {array} quadCorners An array of the quad nodes' corners. - * @return {array} An array of indexes containing one to - * four integers. - */ - function _quadCollision(corners, quadCorners) { - var indexes = []; - - // Iterating through quads - for (var i = 0; i < 4; i++) - if (_geom.collision(corners, quadCorners[i])) - indexes.push(i); - - return indexes; - } - - /** - * Subdivide a quad by creating a node at a precise index. The function does - * not generate all four nodes not to potentially create unused nodes. - * - * @param {integer} index The index of the node to create. - * @param {object} quad The quad object to subdivide. - * @return {object} A new quad representing the node created. - */ - function _quadSubdivide(index, quad) { - var next = quad.level + 1, - subw = Math.round(quad.bounds.width / 2), - subh = Math.round(quad.bounds.height / 2), - qx = Math.round(quad.bounds.x), - qy = Math.round(quad.bounds.y), - x, - y; - - switch (index) { - case 0: - x = qx; - y = qy; - break; - case 1: - x = qx + subw; - y = qy; - break; - case 2: - x = qx; - y = qy + subh; - break; - case 3: - x = qx + subw; - y = qy + subh; - break; - } - - return _quadTree( - {x: x, y: y, width: subw, height: subh}, - next, - quad.maxElements, - quad.maxLevel - ); - } - - /** - * Recursively insert an element into the quadtree. Only points - * with size, i.e. axis-aligned squares, may be inserted with this - * method. - * - * @param {object} el The element to insert in the quadtree. - * @param {object} sizedPoint A sized point defined by two top points - * (x1, y1), (x2, y2) and height. - * @param {object} quad The quad in which to insert the element. - * @return {undefined} The function does not return anything. - */ - function _quadInsert(el, sizedPoint, quad) { - if (quad.level < quad.maxLevel) { - - // Searching appropriate quads - var indexes = _quadIndexes(sizedPoint, quad.corners); - - // Iterating - for (var i = 0, l = indexes.length; i < l; i++) { - - // Subdividing if necessary - if (quad.nodes[indexes[i]] === undefined) - quad.nodes[indexes[i]] = _quadSubdivide(indexes[i], quad); - - // Recursion - _quadInsert(el, sizedPoint, quad.nodes[indexes[i]]); - } - } - else { - - // Pushing the element in a leaf node - quad.elements.push(el); - } - } - - /** - * Recursively retrieve every elements held by the node containing the - * searched point. - * - * @param {object} point The searched point (x, y). - * @param {object} quad The searched quad. - * @return {array} An array of elements contained in the relevant - * node. - */ - function _quadRetrievePoint(point, quad) { - if (quad.level < quad.maxLevel) { - var index = _quadIndex(point, quad.bounds); - - // If node does not exist we return an empty list - if (quad.nodes[index] !== undefined) { - return _quadRetrievePoint(point, quad.nodes[index]); - } - else { - return []; - } - } - else { - return quad.elements; - } - } - - /** - * Recursively retrieve every elements contained within an rectangular area - * that may or may not be axis-aligned. - * - * @param {object|array} rectData The searched area defined either by - * an array of four corners (x, y) in - * the case of a non-axis-aligned - * rectangle or an object with two top - * points (x1, y1), (x2, y2) and height. - * @param {object} quad The searched quad. - * @param {function} collisionFunc The collision function used to search - * for node indexes. - * @param {array?} els The retrieved elements. - * @return {array} An array of elements contained in the - * area. - */ - function _quadRetrieveArea(rectData, quad, collisionFunc, els) { - els = els || {}; - - if (quad.level < quad.maxLevel) { - var indexes = collisionFunc(rectData, quad.corners); - - for (var i = 0, l = indexes.length; i < l; i++) - if (quad.nodes[indexes[i]] !== undefined) - _quadRetrieveArea( - rectData, - quad.nodes[indexes[i]], - collisionFunc, - els - ); - } else - for (var j = 0, m = quad.elements.length; j < m; j++) - if (els[quad.elements[j].id] === undefined) - els[quad.elements[j].id] = quad.elements[j]; - - return els; - } - - /** - * Creates the quadtree object itself. - * - * @param {object} bounds The boundaries of the quad defined by an - * origin (x, y), width and heigth. - * @param {integer} level The level of the quad in the tree. - * @param {integer} maxElements The max number of element in a leaf node. - * @param {integer} maxLevel The max recursion level of the tree. - * @return {object} The quadtree object. - */ - function _quadTree(bounds, level, maxElements, maxLevel) { - return { - level: level || 0, - bounds: bounds, - corners: _geom.splitSquare(bounds), - maxElements: maxElements || 20, - maxLevel: maxLevel || 4, - elements: [], - nodes: [] - }; - } - - - /** - * Sigma Quad Constructor - * ---------------------- - * - * The quad API as exposed to sigma. - */ - - /** - * The quad core that will become the sigma interface with the quadtree. - * - * property {object} _tree Property holding the quadtree object. - * property {object} _geom Exposition of the _geom namespace for testing. - * property {object} _cache Cache for the area method. - */ - var quad = function() { - this._geom = _geom; - this._tree = null; - this._cache = { - query: false, - result: false - }; - }; - - /** - * Index a graph by inserting its nodes into the quadtree. - * - * @param {array} nodes An array of nodes to index. - * @param {object} params An object of parameters with at least the quad - * bounds. - * @return {object} The quadtree object. - * - * Parameters: - * ---------- - * bounds: {object} boundaries of the quad defined by its origin (x, y) - * width and heigth. - * prefix: {string?} a prefix for node geometric attributes. - * maxElements: {integer?} the max number of elements in a leaf node. - * maxLevel: {integer?} the max recursion level of the tree. - */ - quad.prototype.index = function(nodes, params) { - - // Enforcing presence of boundaries - if (!params.bounds) - throw 'sigma.classes.quad.index: bounds information not given.'; - - // Prefix - var prefix = params.prefix || ''; - - // Building the tree - this._tree = _quadTree( - params.bounds, - 0, - params.maxElements, - params.maxLevel - ); - - // Inserting graph nodes into the tree - for (var i = 0, l = nodes.length; i < l; i++) { - - // Inserting node - _quadInsert( - nodes[i], - _geom.pointToSquare({ - x: nodes[i][prefix + 'x'], - y: nodes[i][prefix + 'y'], - size: nodes[i][prefix + 'size'] - }), - this._tree - ); - } - - // Reset cache: - this._cache = { - query: false, - result: false - }; - - // remove? - return this._tree; - }; - - /** - * Retrieve every graph nodes held by the quadtree node containing the - * searched point. - * - * @param {number} x of the point. - * @param {number} y of the point. - * @return {array} An array of nodes retrieved. - */ - quad.prototype.point = function(x, y) { - return this._tree ? - _quadRetrievePoint({x: x, y: y}, this._tree) || [] : - []; - }; - - /** - * Retrieve every graph nodes within a rectangular area. The methods keep the - * last area queried in cache for optimization reason and will act differently - * for the same reason if the area is axis-aligned or not. - * - * @param {object} A rectangle defined by two top points (x1, y1), (x2, y2) - * and height. - * @return {array} An array of nodes retrieved. - */ - quad.prototype.area = function(rect) { - var serialized = JSON.stringify(rect), - collisionFunc, - rectData; - - // Returning cache? - if (this._cache.query === serialized) - return this._cache.result; - - // Axis aligned ? - if (_geom.isAxisAligned(rect)) { - collisionFunc = _quadIndexes; - rectData = _geom.axisAlignedTopPoints(rect); - } - else { - collisionFunc = _quadCollision; - rectData = _geom.rectangleCorners(rect); - } - - // Retrieving nodes - var nodes = this._tree ? - _quadRetrieveArea( - rectData, - this._tree, - collisionFunc - ) : - []; - - // Object to array - var nodesArray = []; - for (var i in nodes) - nodesArray.push(nodes[i]); - - // Caching - this._cache.query = serialized; - this._cache.result = nodesArray; - - return nodesArray; - }; - - - /** - * EXPORT: - * ******* - */ - if (typeof this.sigma !== 'undefined') { - this.sigma.classes = this.sigma.classes || {}; - this.sigma.classes.quad = quad; - } else if (typeof exports !== 'undefined') { - if (typeof module !== 'undefined' && module.exports) - exports = module.exports = quad; - exports.quad = quad; - } else - this.quad = quad; -}).call(this); diff --git a/src/demo/static/sigmajs/conrad.js b/src/demo/static/sigmajs/conrad.js deleted file mode 100644 index 09560d5f6..000000000 --- a/src/demo/static/sigmajs/conrad.js +++ /dev/null @@ -1,984 +0,0 @@ -/** - * conrad.js is a tiny JavaScript jobs scheduler, - * - * Version: 0.1.0 - * Sources: http://github.com/jacomyal/conrad.js - * Doc: http://github.com/jacomyal/conrad.js#readme - * - * License: - * -------- - * Copyright © 2013 Alexis Jacomy, Sciences-Po médialab - * - * 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. - */ -(function(global) { - 'use strict'; - - // Check that conrad.js has not been loaded yet: - if (global.conrad) - throw new Error('conrad already exists'); - - - /** - * PRIVATE VARIABLES: - * ****************** - */ - - /** - * A flag indicating whether conrad is running or not. - * - * @type {Number} - */ - var _lastFrameTime; - - /** - * A flag indicating whether conrad is running or not. - * - * @type {Boolean} - */ - var _isRunning = false; - - /** - * The hash of registered jobs. Each job must at least have a unique ID - * under the key "id" and a function under the key "job". This hash - * contains each running job and each waiting job. - * - * @type {Object} - */ - var _jobs = {}; - - /** - * The hash of currently running jobs. - * - * @type {Object} - */ - var _runningJobs = {}; - - /** - * The array of currently running jobs, sorted by priority. - * - * @type {Array} - */ - var _sortedByPriorityJobs = []; - - /** - * The array of currently waiting jobs. - * - * @type {Object} - */ - var _waitingJobs = {}; - - /** - * The array of finished jobs. They are stored in an array, since two jobs - * with the same "id" can happen at two different times. - * - * @type {Array} - */ - var _doneJobs = []; - - /** - * A dirty flag to keep conrad from starting: Indeed, when addJob() is called - * with several jobs, conrad must be started only at the end. This flag keeps - * me from duplicating the code that effectively adds a job. - * - * @type {Boolean} - */ - var _noStart = false; - - /** - * An hash containing some global settings about how conrad.js should - * behave. - * - * @type {Object} - */ - var _parameters = { - frameDuration: 20, - history: true - }; - - /** - * This object contains every handlers bound to conrad events. It does not - * requirea any DOM implementation, since the events are all JavaScript. - * - * @type {Object} - */ - var _handlers = Object.create(null); - - - /** - * PRIVATE FUNCTIONS: - * ****************** - */ - - /** - * Will execute the handler everytime that the indicated event (or the - * indicated events) will be triggered. - * - * @param {string|array|object} events The name of the event (or the events - * separated by spaces). - * @param {function(Object)} handler The handler to bind. - * @return {Object} Returns conrad. - */ - function _bind(events, handler) { - var i, - i_end, - event, - eArray; - - if (!arguments.length) - return; - else if ( - arguments.length === 1 && - Object(arguments[0]) === arguments[0] - ) - for (events in arguments[0]) - _bind(events, arguments[0][events]); - else if (arguments.length > 1) { - eArray = - Array.isArray(events) ? - events : - events.split(/ /); - - for (i = 0, i_end = eArray.length; i !== i_end; i += 1) { - event = eArray[i]; - - if (!_handlers[event]) - _handlers[event] = []; - - // Using an object instead of directly the handler will make possible - // later to add flags - _handlers[event].push({ - handler: handler - }); - } - } - } - - /** - * Removes the handler from a specified event (or specified events). - * - * @param {?string} events The name of the event (or the events - * separated by spaces). If undefined, - * then all handlers are removed. - * @param {?function(Object)} handler The handler to unbind. If undefined, - * each handler bound to the event or the - * events will be removed. - * @return {Object} Returns conrad. - */ - function _unbind(events, handler) { - var i, - i_end, - j, - j_end, - a, - event, - eArray = Array.isArray(events) ? - events : - events.split(/ /); - - if (!arguments.length) - _handlers = Object.create(null); - else if (handler) { - for (i = 0, i_end = eArray.length; i !== i_end; i += 1) { - event = eArray[i]; - if (_handlers[event]) { - a = []; - for (j = 0, j_end = _handlers[event].length; j !== j_end; j += 1) - if (_handlers[event][j].handler !== handler) - a.push(_handlers[event][j]); - - _handlers[event] = a; - } - - if (_handlers[event] && _handlers[event].length === 0) - delete _handlers[event]; - } - } else - for (i = 0, i_end = eArray.length; i !== i_end; i += 1) - delete _handlers[eArray[i]]; - } - - /** - * Executes each handler bound to the event. - * - * @param {string} events The name of the event (or the events separated - * by spaces). - * @param {?Object} data The content of the event (optional). - * @return {Object} Returns conrad. - */ - function _dispatch(events, data) { - var i, - j, - i_end, - j_end, - event, - eventName, - eArray = Array.isArray(events) ? - events : - events.split(/ /); - - data = data === undefined ? {} : data; - - for (i = 0, i_end = eArray.length; i !== i_end; i += 1) { - eventName = eArray[i]; - - if (_handlers[eventName]) { - event = { - type: eventName, - data: data || {} - }; - - for (j = 0, j_end = _handlers[eventName].length; j !== j_end; j += 1) - try { - _handlers[eventName][j].handler(event); - } catch (e) {} - } - } - } - - /** - * Executes the most prioritary job once, and deals with filling the stats - * (done, time, averageTime, currentTime, etc...). - * - * @return {?Object} Returns the job object if it has to be killed, null else. - */ - function _executeFirstJob() { - var i, - l, - test, - kill, - pushed = false, - time = __dateNow(), - job = _sortedByPriorityJobs.shift(); - - // Execute the job and look at the result: - test = job.job(); - - // Deal with stats: - time = __dateNow() - time; - job.done++; - job.time += time; - job.currentTime += time; - job.weightTime = job.currentTime / (job.weight || 1); - job.averageTime = job.time / job.done; - - // Check if the job has to be killed: - kill = job.count ? (job.count <= job.done) : !test; - - // Reset priorities: - if (!kill) { - for (i = 0, l = _sortedByPriorityJobs.length; i < l; i++) - if (_sortedByPriorityJobs[i].weightTime > job.weightTime) { - _sortedByPriorityJobs.splice(i, 0, job); - pushed = true; - break; - } - - if (!pushed) - _sortedByPriorityJobs.push(job); - } - - return kill ? job : null; - } - - /** - * Activates a job, by adding it to the _runningJobs object and the - * _sortedByPriorityJobs array. It also initializes its currentTime value. - * - * @param {Object} job The job to activate. - */ - function _activateJob(job) { - var l = _sortedByPriorityJobs.length; - - // Add the job to the running jobs: - _runningJobs[job.id] = job; - job.status = 'running'; - - // Add the job to the priorities: - if (l) { - job.weightTime = _sortedByPriorityJobs[l - 1].weightTime; - job.currentTime = job.weightTime * (job.weight || 1); - } - - // Initialize the job and dispatch: - job.startTime = __dateNow(); - _dispatch('jobStarted', __clone(job)); - - _sortedByPriorityJobs.push(job); - } - - /** - * The main loop of conrad.js: - * . It executes job such that they all occupate the same processing time. - * . It stops jobs that do not need to be executed anymore. - * . It triggers callbacks when it is relevant. - * . It starts waiting jobs when they need to be started. - * . It injects frames to keep a constant frapes per second ratio. - * . It stops itself when there are no more jobs to execute. - */ - function _loop() { - var k, - o, - l, - job, - time, - deadJob; - - // Deal with the newly added jobs (the _jobs object): - for (k in _jobs) { - job = _jobs[k]; - - if (job.after) - _waitingJobs[k] = job; - else - _activateJob(job); - - delete _jobs[k]; - } - - // Set the _isRunning flag to false if there are no running job: - _isRunning = !!_sortedByPriorityJobs.length; - - // Deal with the running jobs (the _runningJobs object): - while ( - _sortedByPriorityJobs.length && - __dateNow() - _lastFrameTime < _parameters.frameDuration - ) { - deadJob = _executeFirstJob(); - - // Deal with the case where the job has ended: - if (deadJob) { - _killJob(deadJob.id); - - // Check for waiting jobs: - for (k in _waitingJobs) - if (_waitingJobs[k].after === deadJob.id) { - _activateJob(_waitingJobs[k]); - delete _waitingJobs[k]; - } - } - } - - // Check if conrad still has jobs to deal with, and kill it if not: - if (_isRunning) { - // Update the _lastFrameTime: - _lastFrameTime = __dateNow(); - - _dispatch('enterFrame'); - setTimeout(_loop, 0); - } else - _dispatch('stop'); - } - - /** - * Adds one or more jobs, and starts the loop if no job was running before. A - * job is at least a unique string "id" and a function, and there are some - * parameters that you can specify for each job to modify the way conrad will - * execute it. If a job is added with the "id" of another job that is waiting - * or still running, an error will be thrown. - * - * When a job is added, it is referenced in the _jobs object, by its id. - * Then, if it has to be executed right now, it will be also referenced in - * the _runningJobs object. If it has to wait, then it will be added into the - * _waitingJobs object, until it can start. - * - * Keep reading this documentation to see how to call this method. - * - * @return {Object} Returns conrad. - * - * Adding one job: - * *************** - * Basically, a job is defined by its string id and a function (the job). It - * is also possible to add some parameters: - * - * > conrad.addJob('myJobId', myJobFunction); - * > conrad.addJob('myJobId', { - * > job: myJobFunction, - * > someParameter: someValue - * > }); - * > conrad.addJob({ - * > id: 'myJobId', - * > job: myJobFunction, - * > someParameter: someValue - * > }); - * - * Adding several jobs: - * ******************** - * When adding several jobs at the same time, it is possible to specify - * parameters for each one individually or for all: - * - * > conrad.addJob([ - * > { - * > id: 'myJobId1', - * > job: myJobFunction1, - * > someParameter1: someValue1 - * > }, - * > { - * > id: 'myJobId2', - * > job: myJobFunction2, - * > someParameter2: someValue2 - * > } - * > ], { - * > someCommonParameter: someCommonValue - * > }); - * > conrad.addJob({ - * > myJobId1: {, - * > job: myJobFunction1, - * > someParameter1: someValue1 - * > }, - * > myJobId2: {, - * > job: myJobFunction2, - * > someParameter2: someValue2 - * > } - * > }, { - * > someCommonParameter: someCommonValue - * > }); - * > conrad.addJob({ - * > myJobId1: myJobFunction1, - * > myJobId2: myJobFunction2 - * > }, { - * > someCommonParameter: someCommonValue - * > }); - * - * Recognized parameters: - * ********************** - * Here is the exhaustive list of every accepted parameters: - * - * {?Function} end A callback to execute when the job is ended. It is - * not executed if the job is killed instead of ended - * "naturally". - * {?Integer} count The number of time the job has to be executed. - * {?Number} weight If specified, the job will be executed as it was - * added "weight" times. - * {?String} after The id of another job (eventually not added yet). - * If specified, this job will start only when the - * specified "after" job is ended. - */ - function _addJob(v1, v2) { - var i, - l, - o; - - // Array of jobs: - if (Array.isArray(v1)) { - // Keep conrad to start until the last job is added: - _noStart = true; - - for (i = 0, l = v1.length; i < l; i++) - _addJob(v1[i].id, __extend(v1[i], v2)); - - _noStart = false; - if (!_isRunning) { - // Update the _lastFrameTime: - _lastFrameTime = __dateNow(); - - _dispatch('start'); - _loop(); - } - } else if (typeof v1 === 'object') { - // One job (object): - if (typeof v1.id === 'string') - _addJob(v1.id, v1); - - // Hash of jobs: - else { - // Keep conrad to start until the last job is added: - _noStart = true; - - for (i in v1) - if (typeof v1[i] === 'function') - _addJob(i, __extend({ - job: v1[i] - }, v2)); - else - _addJob(i, __extend(v1[i], v2)); - - _noStart = false; - if (!_isRunning) { - // Update the _lastFrameTime: - _lastFrameTime = __dateNow(); - - _dispatch('start'); - _loop(); - } - } - - // One job (string, *): - } else if (typeof v1 === 'string') { - if (_hasJob(v1)) - throw new Error( - '[conrad.addJob] Job with id "' + v1 + '" already exists.' - ); - - // One job (string, function): - if (typeof v2 === 'function') { - o = { - id: v1, - done: 0, - time: 0, - status: 'waiting', - currentTime: 0, - averageTime: 0, - weightTime: 0, - job: v2 - }; - - // One job (string, object): - } else if (typeof v2 === 'object') { - o = __extend( - { - id: v1, - done: 0, - time: 0, - status: 'waiting', - currentTime: 0, - averageTime: 0, - weightTime: 0 - }, - v2 - ); - - // If none of those cases, throw an error: - } else - throw new Error('[conrad.addJob] Wrong arguments.'); - - // Effectively add the job: - _jobs[v1] = o; - _dispatch('jobAdded', __clone(o)); - - // Check if the loop has to be started: - if (!_isRunning && !_noStart) { - // Update the _lastFrameTime: - _lastFrameTime = __dateNow(); - - _dispatch('start'); - _loop(); - } - - // If none of those cases, throw an error: - } else - throw new Error('[conrad.addJob] Wrong arguments.'); - - return this; - } - - /** - * Kills one or more jobs, indicated by their ids. It is only possible to - * kill running jobs or waiting jobs. If you try to kill a job that does not - * exists or that is already killed, a warning will be thrown. - * - * @param {Array|String} v1 A string job id or an array of job ids. - * @return {Object} Returns conrad. - */ - function _killJob(v1) { - var i, - l, - k, - a, - job, - found = false; - - // Array of job ids: - if (Array.isArray(v1)) - for (i = 0, l = v1.length; i < l; i++) - _killJob(v1[i]); - - // One job's id: - else if (typeof v1 === 'string') { - a = [_runningJobs, _waitingJobs, _jobs]; - - // Remove the job from the hashes: - for (i = 0, l = a.length; i < l; i++) - if (v1 in a[i]) { - job = a[i][v1]; - - if (_parameters.history) { - job.status = 'done'; - _doneJobs.push(job); - } - - _dispatch('jobEnded', __clone(job)); - delete a[i][v1]; - - if (typeof job.end === 'function') - job.end(); - - found = true; - } - - // Remove the priorities array: - a = _sortedByPriorityJobs; - for (i = 0, l = a.length; i < l; i++) - if (a[i].id === v1) { - a.splice(i, 1); - break; - } - - if (!found) - throw new Error('[conrad.killJob] Job "' + v1 + '" not found.'); - - // If none of those cases, throw an error: - } else - throw new Error('[conrad.killJob] Wrong arguments.'); - - return this; - } - - /** - * Kills every running, waiting, and just added jobs. - * - * @return {Object} Returns conrad. - */ - function _killAll() { - var k, - jobs = __extend(_jobs, _runningJobs, _waitingJobs); - - // Take every jobs and push them into the _doneJobs object: - if (_parameters.history) - for (k in jobs) { - jobs[k].status = 'done'; - _doneJobs.push(jobs[k]); - - if (typeof jobs[k].end === 'function') - jobs[k].end(); - } - - // Reinitialize the different jobs lists: - _jobs = {}; - _waitingJobs = {}; - _runningJobs = {}; - _sortedByPriorityJobs = []; - - // In case some jobs are added right after the kill: - _isRunning = false; - - return this; - } - - /** - * Returns true if a job with the specified id is currently running or - * waiting, and false else. - * - * @param {String} id The id of the job. - * @return {?Object} Returns the job object if it exists. - */ - function _hasJob(id) { - var job = _jobs[id] || _runningJobs[id] || _waitingJobs[id]; - return job ? __extend(job) : null; - } - - /** - * This method will set the setting specified by "v1" to the value specified - * by "v2" if both are given, and else return the current value of the - * settings "v1". - * - * @param {String} v1 The name of the property. - * @param {?*} v2 Eventually, a value to set to the specified - * property. - * @return {Object|*} Returns the specified settings value if "v2" is not - * given, and conrad else. - */ - function _settings(v1, v2) { - var o; - - if (typeof a1 === 'string' && arguments.length === 1) - return _parameters[a1]; - else { - o = (typeof a1 === 'object' && arguments.length === 1) ? - a1 || {} : - {}; - if (typeof a1 === 'string') - o[a1] = a2; - - for (var k in o) - if (o[k] !== undefined) - _parameters[k] = o[k]; - else - delete _parameters[k]; - - return this; - } - } - - /** - * Returns true if conrad is currently running, and false else. - * - * @return {Boolean} Returns _isRunning. - */ - function _getIsRunning() { - return _isRunning; - } - - /** - * Unreference every jobs that are stored in the _doneJobs object. It will - * not be possible anymore to get stats about these jobs, but it will release - * the memory. - * - * @return {Object} Returns conrad. - */ - function _clearHistory() { - _doneJobs = []; - return this; - } - - /** - * Returns a snapshot of every data about jobs that wait to be started, are - * currently running or are done. - * - * It is possible to get only running, waiting or done jobs by giving - * "running", "waiting" or "done" as fist argument. - * - * It is also possible to get every job with a specified id by giving it as - * first argument. Also, using a RegExp instead of an id will return every - * jobs whose ids match the RegExp. And these two last use cases work as well - * by giving before "running", "waiting" or "done". - * - * @return {Array} The array of the matching jobs. - * - * Some call examples: - * ******************* - * > conrad.getStats('running') - * > conrad.getStats('waiting') - * > conrad.getStats('done') - * > conrad.getStats('myJob') - * > conrad.getStats(/test/) - * > conrad.getStats('running', 'myRunningJob') - * > conrad.getStats('running', /test/) - */ - function _getStats(v1, v2) { - var a, - k, - i, - l, - stats, - pattern, - isPatternString; - - if (!arguments.length) { - stats = []; - - for (k in _jobs) - stats.push(_jobs[k]); - - for (k in _waitingJobs) - stats.push(_waitingJobs[k]); - - for (k in _runningJobs) - stats.push(_runningJobs[k]); - - stats = stats.concat(_doneJobs); - } - - if (typeof v1 === 'string') - switch (v1) { - case 'waiting': - stats = __objectValues(_waitingJobs); - break; - case 'running': - stats = __objectValues(_runningJobs); - break; - case 'done': - stats = _doneJobs; - break; - default: - pattern = v1; - } - - if (v1 instanceof RegExp) - pattern = v1; - - if (!pattern && (typeof v2 === 'string' || v2 instanceof RegExp)) - pattern = v2; - - // Filter jobs if a pattern is given: - if (pattern) { - isPatternString = typeof pattern === 'string'; - - if (stats instanceof Array) { - a = stats; - } else if (typeof stats === 'object') { - a = []; - - for (k in stats) - a = a.concat(stats[k]); - } else { - a = []; - - for (k in _jobs) - a.push(_jobs[k]); - - for (k in _waitingJobs) - a.push(_waitingJobs[k]); - - for (k in _runningJobs) - a.push(_runningJobs[k]); - - a = a.concat(_doneJobs); - } - - stats = []; - for (i = 0, l = a.length; i < l; i++) - if (isPatternString ? a[i].id === pattern : a[i].id.match(pattern)) - stats.push(a[i]); - } - - return __clone(stats); - } - - - /** - * TOOLS FUNCTIONS: - * **************** - */ - - /** - * This function takes any number of objects as arguments, copies from each - * of these objects each pair key/value into a new object, and finally - * returns this object. - * - * The arguments are parsed from the last one to the first one, such that - * when two objects have keys in common, the "earliest" object wins. - * - * Example: - * ******** - * > var o1 = { - * > a: 1, - * > b: 2, - * > c: '3' - * > }, - * > o2 = { - * > c: '4', - * > d: [ 5 ] - * > }; - * > __extend(o1, o2); - * > // Returns: { - * > // a: 1, - * > // b: 2, - * > // c: '3', - * > // d: [ 5 ] - * > // }; - * - * @param {Object+} Any number of objects. - * @return {Object} The merged object. - */ - function __extend() { - var i, - k, - res = {}, - l = arguments.length; - - for (i = l - 1; i >= 0; i--) - for (k in arguments[i]) - res[k] = arguments[i][k]; - - return res; - } - - /** - * This function simply clones an object. This object must contain only - * objects, arrays and immutable values. Since it is not public, it does not - * deal with cyclic references, DOM elements and instantiated objects - so - * use it carefully. - * - * @param {Object} The object to clone. - * @return {Object} The clone. - */ - function __clone(item) { - var result, i, k, l; - - if (!item) - return item; - - if (Array.isArray(item)) { - result = []; - for (i = 0, l = item.length; i < l; i++) - result.push(__clone(item[i])); - } else if (typeof item === 'object') { - result = {}; - for (i in item) - result[i] = __clone(item[i]); - } else - result = item; - - return result; - } - - /** - * Returns an array containing the values of an object. - * - * @param {Object} The object. - * @return {Array} The array of values. - */ - function __objectValues(o) { - var k, - a = []; - - for (k in o) - a.push(o[k]); - - return a; - } - - /** - * A short "Date.now()" polyfill. - * - * @return {Number} The current time (in ms). - */ - function __dateNow() { - return Date.now ? Date.now() : new Date().getTime(); - } - - /** - * Polyfill for the Array.isArray function: - */ - if (!Array.isArray) - Array.isArray = function(v) { - return Object.prototype.toString.call(v) === '[object Array]'; - }; - - - /** - * EXPORT PUBLIC API: - * ****************** - */ - var conrad = { - hasJob: _hasJob, - addJob: _addJob, - killJob: _killJob, - killAll: _killAll, - settings: _settings, - getStats: _getStats, - isRunning: _getIsRunning, - clearHistory: _clearHistory, - - // Events management: - bind: _bind, - unbind: _unbind, - - // Version: - version: '0.1.0' - }; - - if (typeof exports !== 'undefined') { - if (typeof module !== 'undefined' && module.exports) - exports = module.exports = conrad; - exports.conrad = conrad; - } - global.conrad = conrad; -})(this); diff --git a/src/demo/static/sigmajs/middlewares/sigma.middlewares.copy.js b/src/demo/static/sigmajs/middlewares/sigma.middlewares.copy.js deleted file mode 100644 index 8f1b2a947..000000000 --- a/src/demo/static/sigmajs/middlewares/sigma.middlewares.copy.js +++ /dev/null @@ -1,35 +0,0 @@ -;(function(undefined) { - 'use strict'; - - if (typeof sigma === 'undefined') - throw 'sigma is not declared'; - - // Initialize packages: - sigma.utils.pkg('sigma.middlewares'); - - /** - * This middleware will just copy the graphic properties. - * - * @param {?string} readPrefix The read prefix. - * @param {?string} writePrefix The write prefix. - */ - sigma.middlewares.copy = function(readPrefix, writePrefix) { - var i, - l, - a; - - if (writePrefix + '' === readPrefix + '') - return; - - a = this.graph.nodes(); - for (i = 0, l = a.length; i < l; i++) { - a[i][writePrefix + 'x'] = a[i][readPrefix + 'x']; - a[i][writePrefix + 'y'] = a[i][readPrefix + 'y']; - a[i][writePrefix + 'size'] = a[i][readPrefix + 'size']; - } - - a = this.graph.edges(); - for (i = 0, l = a.length; i < l; i++) - a[i][writePrefix + 'size'] = a[i][readPrefix + 'size']; - }; -}).call(this); diff --git a/src/demo/static/sigmajs/middlewares/sigma.middlewares.rescale.js b/src/demo/static/sigmajs/middlewares/sigma.middlewares.rescale.js deleted file mode 100644 index 85460ec2b..000000000 --- a/src/demo/static/sigmajs/middlewares/sigma.middlewares.rescale.js +++ /dev/null @@ -1,189 +0,0 @@ -;(function(undefined) { - 'use strict'; - - if (typeof sigma === 'undefined') - throw 'sigma is not declared'; - - // Initialize packages: - sigma.utils.pkg('sigma.middlewares'); - sigma.utils.pkg('sigma.utils'); - - /** - * This middleware will rescale the graph such that it takes an optimal space - * on the renderer. - * - * As each middleware, this function is executed in the scope of the sigma - * instance. - * - * @param {?string} readPrefix The read prefix. - * @param {?string} writePrefix The write prefix. - * @param {object} options The parameters. - */ - sigma.middlewares.rescale = function(readPrefix, writePrefix, options) { - var i, - l, - a, - b, - c, - d, - scale, - margin, - n = this.graph.nodes(), - e = this.graph.edges(), - settings = this.settings.embedObjects(options || {}), - bounds = settings('bounds') || sigma.utils.getBoundaries( - this.graph, - readPrefix, - true - ), - minX = bounds.minX, - minY = bounds.minY, - maxX = bounds.maxX, - maxY = bounds.maxY, - sizeMax = bounds.sizeMax, - weightMax = bounds.weightMax, - w = settings('width') || 1, - h = settings('height') || 1, - rescaleSettings = settings('autoRescale'), - validSettings = { - nodePosition: 1, - nodeSize: 1, - edgeSize: 1 - }; - - /** - * What elements should we rescale? - */ - if (!(rescaleSettings instanceof Array)) - rescaleSettings = ['nodePosition', 'nodeSize', 'edgeSize']; - - for (i = 0, l = rescaleSettings.length; i < l; i++) - if (!validSettings[rescaleSettings[i]]) - throw new Error( - 'The rescale setting "' + rescaleSettings[i] + '" is not recognized.' - ); - - var np = ~rescaleSettings.indexOf('nodePosition'), - ns = ~rescaleSettings.indexOf('nodeSize'), - es = ~rescaleSettings.indexOf('edgeSize'); - - /** - * First, we compute the scaling ratio, without considering the sizes - * of the nodes : Each node will have its center in the canvas, but might - * be partially out of it. - */ - scale = settings('scalingMode') === 'outside' ? - Math.max( - w / Math.max(maxX - minX, 1), - h / Math.max(maxY - minY, 1) - ) : - Math.min( - w / Math.max(maxX - minX, 1), - h / Math.max(maxY - minY, 1) - ); - - /** - * Then, we correct that scaling ratio considering a margin, which is - * basically the size of the biggest node. - * This has to be done as a correction since to compare the size of the - * biggest node to the X and Y values, we have to first get an - * approximation of the scaling ratio. - **/ - margin = - ( - settings('rescaleIgnoreSize') ? - 0 : - (settings('maxNodeSize') || sizeMax) / scale - ) + - (settings('sideMargin') || 0); - maxX += margin; - minX -= margin; - maxY += margin; - minY -= margin; - - // Fix the scaling with the new extrema: - scale = settings('scalingMode') === 'outside' ? - Math.max( - w / Math.max(maxX - minX, 1), - h / Math.max(maxY - minY, 1) - ) : - Math.min( - w / Math.max(maxX - minX, 1), - h / Math.max(maxY - minY, 1) - ); - - // Size homothetic parameters: - if (!settings('maxNodeSize') && !settings('minNodeSize')) { - a = 1; - b = 0; - } else if (settings('maxNodeSize') === settings('minNodeSize')) { - a = 0; - b = +settings('maxNodeSize'); - } else { - a = (settings('maxNodeSize') - settings('minNodeSize')) / sizeMax; - b = +settings('minNodeSize'); - } - - if (!settings('maxEdgeSize') && !settings('minEdgeSize')) { - c = 1; - d = 0; - } else if (settings('maxEdgeSize') === settings('minEdgeSize')) { - c = 0; - d = +settings('minEdgeSize'); - } else { - c = (settings('maxEdgeSize') - settings('minEdgeSize')) / weightMax; - d = +settings('minEdgeSize'); - } - - // Rescale the nodes and edges: - for (i = 0, l = e.length; i < l; i++) - e[i][writePrefix + 'size'] = - e[i][readPrefix + 'size'] * (es ? c : 1) + (es ? d : 0); - - for (i = 0, l = n.length; i < l; i++) { - n[i][writePrefix + 'size'] = - n[i][readPrefix + 'size'] * (ns ? a : 1) + (ns ? b : 0); - n[i][writePrefix + 'x'] = - (n[i][readPrefix + 'x'] - (maxX + minX) / 2) * (np ? scale : 1); - n[i][writePrefix + 'y'] = - (n[i][readPrefix + 'y'] - (maxY + minY) / 2) * (np ? scale : 1); - } - }; - - sigma.utils.getBoundaries = function(graph, prefix, doEdges) { - var i, - l, - e = graph.edges(), - n = graph.nodes(), - weightMax = -Infinity, - sizeMax = -Infinity, - minX = Infinity, - minY = Infinity, - maxX = -Infinity, - maxY = -Infinity; - - if (doEdges) - for (i = 0, l = e.length; i < l; i++) - weightMax = Math.max(e[i][prefix + 'size'], weightMax); - - for (i = 0, l = n.length; i < l; i++) { - sizeMax = Math.max(n[i][prefix + 'size'], sizeMax); - maxX = Math.max(n[i][prefix + 'x'], maxX); - minX = Math.min(n[i][prefix + 'x'], minX); - maxY = Math.max(n[i][prefix + 'y'], maxY); - minY = Math.min(n[i][prefix + 'y'], minY); - } - - weightMax = weightMax || 1; - sizeMax = sizeMax || 1; - - return { - weightMax: weightMax, - sizeMax: sizeMax, - minX: minX, - minY: minY, - maxX: maxX, - maxY: maxY - }; - }; -}).call(this); diff --git a/src/demo/static/sigmajs/misc/sigma.misc.animation.js b/src/demo/static/sigmajs/misc/sigma.misc.animation.js deleted file mode 100644 index 299f00fe1..000000000 --- a/src/demo/static/sigmajs/misc/sigma.misc.animation.js +++ /dev/null @@ -1,239 +0,0 @@ -;(function(undefined) { - 'use strict'; - - if (typeof sigma === 'undefined') - throw 'sigma is not declared'; - - // Initialize packages: - sigma.utils.pkg('sigma.misc.animation.running'); - - /** - * Generates a unique ID for the animation. - * - * @return {string} Returns the new ID. - */ - var _getID = (function() { - var id = 0; - return function() { - return '' + (++id); - }; - })(); - - /** - * This function animates a camera. It has to be called with the camera to - * animate, the values of the coordinates to reach and eventually some - * options. It returns a number id, that you can use to kill the animation, - * with the method sigma.misc.animation.kill(id). - * - * The available options are: - * - * {?number} duration The duration of the animation. - * {?function} onNewFrame A callback to execute when the animation - * enter a new frame. - * {?function} onComplete A callback to execute when the animation - * is completed or killed. - * {?(string|function)} easing The name of a function from the package - * sigma.utils.easings, or a custom easing - * function. - * - * @param {camera} camera The camera to animate. - * @param {object} target The coordinates to reach. - * @param {?object} options Eventually an object to specify some options to - * the function. The available options are - * presented in the description of the function. - * @return {number} The animation id, to make it easy to kill - * through the method "sigma.misc.animation.kill". - */ - sigma.misc.animation.camera = function(camera, val, options) { - if ( - !(camera instanceof sigma.classes.camera) || - typeof val !== 'object' || - !val - ) - throw 'animation.camera: Wrong arguments.'; - - if ( - typeof val.x !== 'number' && - typeof val.y !== 'number' && - typeof val.ratio !== 'number' && - typeof val.angle !== 'number' - ) - throw 'There must be at least one valid coordinate in the given val.'; - - var fn, - id, - anim, - easing, - duration, - initialVal, - o = options || {}, - start = sigma.utils.dateNow(); - - // Store initial values: - initialVal = { - x: camera.x, - y: camera.y, - ratio: camera.ratio, - angle: camera.angle - }; - - duration = o.duration; - easing = typeof o.easing !== 'function' ? - sigma.utils.easings[o.easing || 'quadraticInOut'] : - o.easing; - - fn = function() { - var coef, - t = o.duration ? (sigma.utils.dateNow() - start) / o.duration : 1; - - // If the animation is over: - if (t >= 1) { - camera.isAnimated = false; - camera.goTo({ - x: val.x !== undefined ? val.x : initialVal.x, - y: val.y !== undefined ? val.y : initialVal.y, - ratio: val.ratio !== undefined ? val.ratio : initialVal.ratio, - angle: val.angle !== undefined ? val.angle : initialVal.angle - }); - - cancelAnimationFrame(id); - delete sigma.misc.animation.running[id]; - - // Check callbacks: - if (typeof o.onComplete === 'function') - o.onComplete(); - - // Else, let's keep going: - } else { - coef = easing(t); - camera.isAnimated = true; - camera.goTo({ - x: val.x !== undefined ? - initialVal.x + (val.x - initialVal.x) * coef : - initialVal.x, - y: val.y !== undefined ? - initialVal.y + (val.y - initialVal.y) * coef : - initialVal.y, - ratio: val.ratio !== undefined ? - initialVal.ratio + (val.ratio - initialVal.ratio) * coef : - initialVal.ratio, - angle: val.angle !== undefined ? - initialVal.angle + (val.angle - initialVal.angle) * coef : - initialVal.angle - }); - - // Check callbacks: - if (typeof o.onNewFrame === 'function') - o.onNewFrame(); - - anim.frameId = requestAnimationFrame(fn); - } - }; - - id = _getID(); - anim = { - frameId: requestAnimationFrame(fn), - target: camera, - type: 'camera', - options: o, - fn: fn - }; - sigma.misc.animation.running[id] = anim; - - return id; - }; - - /** - * Kills a running animation. It triggers the eventual onComplete callback. - * - * @param {number} id The id of the animation to kill. - * @return {object} Returns the sigma.misc.animation package. - */ - sigma.misc.animation.kill = function(id) { - if (arguments.length !== 1 || typeof id !== 'number') - throw 'animation.kill: Wrong arguments.'; - - var o = sigma.misc.animation.running[id]; - - if (o) { - cancelAnimationFrame(id); - delete sigma.misc.animation.running[o.frameId]; - - if (o.type === 'camera') - o.target.isAnimated = false; - - // Check callbacks: - if (typeof (o.options || {}).onComplete === 'function') - o.options.onComplete(); - } - - return this; - }; - - /** - * Kills every running animations, or only the one with the specified type, - * if a string parameter is given. - * - * @param {?(string|object)} filter A string to filter the animations to kill - * on their type (example: "camera"), or an - * object to filter on their target. - * @return {number} Returns the number of animations killed - * that way. - */ - sigma.misc.animation.killAll = function(filter) { - var o, - id, - count = 0, - type = typeof filter === 'string' ? filter : null, - target = typeof filter === 'object' ? filter : null, - running = sigma.misc.animation.running; - - for (id in running) - if ( - (!type || running[id].type === type) && - (!target || running[id].target === target) - ) { - o = sigma.misc.animation.running[id]; - cancelAnimationFrame(o.frameId); - delete sigma.misc.animation.running[id]; - - if (o.type === 'camera') - o.target.isAnimated = false; - - // Increment counter: - count++; - - // Check callbacks: - if (typeof (o.options || {}).onComplete === 'function') - o.options.onComplete(); - } - - return count; - }; - - /** - * Returns "true" if any animation that is currently still running matches - * the filter given to the function. - * - * @param {string|object} filter A string to filter the animations to kill - * on their type (example: "camera"), or an - * object to filter on their target. - * @return {boolean} Returns true if any running animation - * matches. - */ - sigma.misc.animation.has = function(filter) { - var id, - type = typeof filter === 'string' ? filter : null, - target = typeof filter === 'object' ? filter : null, - running = sigma.misc.animation.running; - - for (id in running) - if ( - (!type || running[id].type === type) && - (!target || running[id].target === target) - ) - return true; - - return false; - }; -}).call(this); diff --git a/src/demo/static/sigmajs/misc/sigma.misc.bindDOMEvents.js b/src/demo/static/sigmajs/misc/sigma.misc.bindDOMEvents.js deleted file mode 100644 index 1e758e848..000000000 --- a/src/demo/static/sigmajs/misc/sigma.misc.bindDOMEvents.js +++ /dev/null @@ -1,156 +0,0 @@ -;(function(undefined) { - 'use strict'; - - if (typeof sigma === 'undefined') - throw 'sigma is not declared'; - - // Initialize packages: - sigma.utils.pkg('sigma.misc'); - - /** - * This helper will bind any DOM renderer (for instance svg) - * to its captors, to properly dispatch the good events to the sigma instance - * to manage clicking, hovering etc... - * - * It has to be called in the scope of the related renderer. - */ - sigma.misc.bindDOMEvents = function(container) { - var self = this, - graph = this.graph; - - // DOMElement abstraction - function Element(domElement) { - - // Helpers - this.attr = function(attrName) { - return domElement.getAttributeNS(null, attrName); - }; - - // Properties - this.tag = domElement.tagName; - this.class = this.attr('class'); - this.id = this.attr('id'); - - // Methods - this.isNode = function() { - return !!~this.class.indexOf(self.settings('classPrefix') + '-node'); - }; - - this.isEdge = function() { - return !!~this.class.indexOf(self.settings('classPrefix') + '-edge'); - }; - - this.isHover = function() { - return !!~this.class.indexOf(self.settings('classPrefix') + '-hover'); - }; - } - - // Click - function click(e) { - if (!self.settings('eventsEnabled')) - return; - - // Generic event - self.dispatchEvent('click', e); - - // Are we on a node? - var element = new Element(e.target); - - if (element.isNode()) - self.dispatchEvent('clickNode', { - node: graph.nodes(element.attr('data-node-id')) - }); - else - self.dispatchEvent('clickStage'); - - e.preventDefault(); - e.stopPropagation(); - } - - // Double click - function doubleClick(e) { - if (!self.settings('eventsEnabled')) - return; - - // Generic event - self.dispatchEvent('doubleClick', e); - - // Are we on a node? - var element = new Element(e.target); - - if (element.isNode()) - self.dispatchEvent('doubleClickNode', { - node: graph.nodes(element.attr('data-node-id')) - }); - else - self.dispatchEvent('doubleClickStage'); - - e.preventDefault(); - e.stopPropagation(); - } - - // On over - function onOver(e) { - var target = e.toElement || e.target; - - if (!self.settings('eventsEnabled') || !target) - return; - - var el = new Element(target); - - if (el.isNode()) { - self.dispatchEvent('overNode', { - node: graph.nodes(el.attr('data-node-id')) - }); - } - else if (el.isEdge()) { - var edge = graph.edges(el.attr('data-edge-id')); - self.dispatchEvent('overEdge', { - edge: edge, - source: graph.nodes(edge.source), - target: graph.nodes(edge.target) - }); - } - } - - // On out - function onOut(e) { - var target = e.fromElement || e.originalTarget; - - if (!self.settings('eventsEnabled')) - return; - - var el = new Element(target); - - if (el.isNode()) { - self.dispatchEvent('outNode', { - node: graph.nodes(el.attr('data-node-id')) - }); - } - else if (el.isEdge()) { - var edge = graph.edges(el.attr('data-edge-id')); - self.dispatchEvent('outEdge', { - edge: edge, - source: graph.nodes(edge.source), - target: graph.nodes(edge.target) - }); - } - } - - // Registering Events: - - // Click - container.addEventListener('click', click, false); - sigma.utils.doubleClick(container, 'click', doubleClick); - - // Touch counterparts - container.addEventListener('touchstart', click, false); - sigma.utils.doubleClick(container, 'touchstart', doubleClick); - - // Mouseover - container.addEventListener('mouseover', onOver, true); - - // Mouseout - container.addEventListener('mouseout', onOut, true); - }; -}).call(this); diff --git a/src/demo/static/sigmajs/misc/sigma.misc.bindEvents.js b/src/demo/static/sigmajs/misc/sigma.misc.bindEvents.js deleted file mode 100644 index e87ad028d..000000000 --- a/src/demo/static/sigmajs/misc/sigma.misc.bindEvents.js +++ /dev/null @@ -1,509 +0,0 @@ -;(function(undefined) { - 'use strict'; - - if (typeof sigma === 'undefined') - throw 'sigma is not declared'; - - // Initialize packages: - sigma.utils.pkg('sigma.misc'); - - /** - * This helper will bind any no-DOM renderer (for instance canvas or WebGL) - * to its captors, to properly dispatch the good events to the sigma instance - * to manage clicking, hovering etc... - * - * It has to be called in the scope of the related renderer. - */ - sigma.misc.bindEvents = function(prefix) { - var i, - l, - mX, - mY, - captor, - self = this; - - function getNodes(e) { - if (e) { - mX = 'x' in e.data ? e.data.x : mX; - mY = 'y' in e.data ? e.data.y : mY; - } - - var i, - j, - l, - n, - x, - y, - s, - inserted, - selected = [], - modifiedX = mX + self.width / 2, - modifiedY = mY + self.height / 2, - point = self.camera.cameraPosition( - mX, - mY - ), - nodes = self.camera.quadtree.point( - point.x, - point.y - ); - - if (nodes.length) - for (i = 0, l = nodes.length; i < l; i++) { - n = nodes[i]; - x = n[prefix + 'x']; - y = n[prefix + 'y']; - s = n[prefix + 'size']; - - if ( - !n.hidden && - modifiedX > x - s && - modifiedX < x + s && - modifiedY > y - s && - modifiedY < y + s && - Math.sqrt( - Math.pow(modifiedX - x, 2) + - Math.pow(modifiedY - y, 2) - ) < s - ) { - // Insert the node: - inserted = false; - - for (j = 0; j < selected.length; j++) - if (n.size > selected[j].size) { - selected.splice(j, 0, n); - inserted = true; - break; - } - - if (!inserted) - selected.push(n); - } - } - - return selected; - } - - - function getEdges(e) { - if (!self.settings('enableEdgeHovering')) { - // No event if the setting is off: - return []; - } - - var isCanvas = ( - sigma.renderers.canvas && self instanceof sigma.renderers.canvas); - - if (!isCanvas) { - // A quick hardcoded rule to prevent people from using this feature - // with the WebGL renderer (which is not good enough at the moment): - throw new Error( - 'The edge events feature is not compatible with the WebGL renderer' - ); - } - - if (e) { - mX = 'x' in e.data ? e.data.x : mX; - mY = 'y' in e.data ? e.data.y : mY; - } - - var i, - j, - l, - a, - edge, - s, - maxEpsilon = self.settings('edgeHoverPrecision'), - source, - target, - cp, - nodeIndex = {}, - inserted, - selected = [], - modifiedX = mX + self.width / 2, - modifiedY = mY + self.height / 2, - point = self.camera.cameraPosition( - mX, - mY - ), - edges = []; - - if (isCanvas) { - var nodesOnScreen = self.camera.quadtree.area( - self.camera.getRectangle(self.width, self.height) - ); - for (a = nodesOnScreen, i = 0, l = a.length; i < l; i++) - nodeIndex[a[i].id] = a[i]; - } - - if (self.camera.edgequadtree !== undefined) { - edges = self.camera.edgequadtree.point( - point.x, - point.y - ); - } - - function insertEdge(selected, edge) { - inserted = false; - - for (j = 0; j < selected.length; j++) - if (edge.size > selected[j].size) { - selected.splice(j, 0, edge); - inserted = true; - break; - } - - if (!inserted) - selected.push(edge); - } - - if (edges.length) - for (i = 0, l = edges.length; i < l; i++) { - edge = edges[i]; - source = self.graph.nodes(edge.source); - target = self.graph.nodes(edge.target); - // (HACK) we can't get edge[prefix + 'size'] on WebGL renderer: - s = edge[prefix + 'size'] || - edge['read_' + prefix + 'size']; - - // First, let's identify which edges are drawn. To do this, we keep - // every edges that have at least one extremity displayed according to - // the quadtree and the "hidden" attribute. We also do not keep hidden - // edges. - // Then, let's check if the mouse is on the edge (we suppose that it - // is a line segment). - - if ( - !edge.hidden && - !source.hidden && !target.hidden && - (!isCanvas || - (nodeIndex[edge.source] || nodeIndex[edge.target])) && - sigma.utils.getDistance( - source[prefix + 'x'], - source[prefix + 'y'], - modifiedX, - modifiedY) > source[prefix + 'size'] && - sigma.utils.getDistance( - target[prefix + 'x'], - target[prefix + 'y'], - modifiedX, - modifiedY) > target[prefix + 'size'] - ) { - if (edge.type == 'curve' || edge.type == 'curvedArrow') { - if (source.id === target.id) { - cp = sigma.utils.getSelfLoopControlPoints( - source[prefix + 'x'], - source[prefix + 'y'], - source[prefix + 'size'] - ); - if ( - sigma.utils.isPointOnBezierCurve( - modifiedX, - modifiedY, - source[prefix + 'x'], - source[prefix + 'y'], - target[prefix + 'x'], - target[prefix + 'y'], - cp.x1, - cp.y1, - cp.x2, - cp.y2, - Math.max(s, maxEpsilon) - )) { - insertEdge(selected, edge); - } - } - else { - cp = sigma.utils.getQuadraticControlPoint( - source[prefix + 'x'], - source[prefix + 'y'], - target[prefix + 'x'], - target[prefix + 'y']); - if ( - sigma.utils.isPointOnQuadraticCurve( - modifiedX, - modifiedY, - source[prefix + 'x'], - source[prefix + 'y'], - target[prefix + 'x'], - target[prefix + 'y'], - cp.x, - cp.y, - Math.max(s, maxEpsilon) - )) { - insertEdge(selected, edge); - } - } - } else if ( - sigma.utils.isPointOnSegment( - modifiedX, - modifiedY, - source[prefix + 'x'], - source[prefix + 'y'], - target[prefix + 'x'], - target[prefix + 'y'], - Math.max(s, maxEpsilon) - )) { - insertEdge(selected, edge); - } - } - } - - return selected; - } - - - function bindCaptor(captor) { - var nodes, - edges, - overNodes = {}, - overEdges = {}; - - function onClick(e) { - if (!self.settings('eventsEnabled')) - return; - - self.dispatchEvent('click', e.data); - - nodes = getNodes(e); - edges = getEdges(e); - - if (nodes.length) { - self.dispatchEvent('clickNode', { - node: nodes[0], - captor: e.data - }); - self.dispatchEvent('clickNodes', { - node: nodes, - captor: e.data - }); - } else if (edges.length) { - self.dispatchEvent('clickEdge', { - edge: edges[0], - captor: e.data - }); - self.dispatchEvent('clickEdges', { - edge: edges, - captor: e.data - }); - } else - self.dispatchEvent('clickStage', {captor: e.data}); - } - - function onDoubleClick(e) { - if (!self.settings('eventsEnabled')) - return; - - self.dispatchEvent('doubleClick', e.data); - - nodes = getNodes(e); - edges = getEdges(e); - - if (nodes.length) { - self.dispatchEvent('doubleClickNode', { - node: nodes[0], - captor: e.data - }); - self.dispatchEvent('doubleClickNodes', { - node: nodes, - captor: e.data - }); - } else if (edges.length) { - self.dispatchEvent('doubleClickEdge', { - edge: edges[0], - captor: e.data - }); - self.dispatchEvent('doubleClickEdges', { - edge: edges, - captor: e.data - }); - } else - self.dispatchEvent('doubleClickStage', {captor: e.data}); - } - - function onRightClick(e) { - if (!self.settings('eventsEnabled')) - return; - - self.dispatchEvent('rightClick', e.data); - - nodes = getNodes(e); - edges = getEdges(e); - - if (nodes.length) { - self.dispatchEvent('rightClickNode', { - node: nodes[0], - captor: e.data - }); - self.dispatchEvent('rightClickNodes', { - node: nodes, - captor: e.data - }); - } else if (edges.length) { - self.dispatchEvent('rightClickEdge', { - edge: edges[0], - captor: e.data - }); - self.dispatchEvent('rightClickEdges', { - edge: edges, - captor: e.data - }); - } else - self.dispatchEvent('rightClickStage', {captor: e.data}); - } - - function onOut(e) { - if (!self.settings('eventsEnabled')) - return; - - var k, - i, - l, - le, - outNodes = [], - outEdges = []; - - for (k in overNodes) - outNodes.push(overNodes[k]); - - overNodes = {}; - // Dispatch both single and multi events: - for (i = 0, l = outNodes.length; i < l; i++) - self.dispatchEvent('outNode', { - node: outNodes[i], - captor: e.data - }); - if (outNodes.length) - self.dispatchEvent('outNodes', { - nodes: outNodes, - captor: e.data - }); - - overEdges = {}; - // Dispatch both single and multi events: - for (i = 0, le = outEdges.length; i < le; i++) - self.dispatchEvent('outEdge', { - edge: outEdges[i], - captor: e.data - }); - if (outEdges.length) - self.dispatchEvent('outEdges', { - edges: outEdges, - captor: e.data - }); - } - - function onMove(e) { - if (!self.settings('eventsEnabled')) - return; - - nodes = getNodes(e); - edges = getEdges(e); - - var i, - k, - node, - edge, - newOutNodes = [], - newOverNodes = [], - currentOverNodes = {}, - l = nodes.length, - newOutEdges = [], - newOverEdges = [], - currentOverEdges = {}, - le = edges.length; - - // Check newly overred nodes: - for (i = 0; i < l; i++) { - node = nodes[i]; - currentOverNodes[node.id] = node; - if (!overNodes[node.id]) { - newOverNodes.push(node); - overNodes[node.id] = node; - } - } - - // Check no more overred nodes: - for (k in overNodes) - if (!currentOverNodes[k]) { - newOutNodes.push(overNodes[k]); - delete overNodes[k]; - } - - // Dispatch both single and multi events: - for (i = 0, l = newOverNodes.length; i < l; i++) - self.dispatchEvent('overNode', { - node: newOverNodes[i], - captor: e.data - }); - for (i = 0, l = newOutNodes.length; i < l; i++) - self.dispatchEvent('outNode', { - node: newOutNodes[i], - captor: e.data - }); - if (newOverNodes.length) - self.dispatchEvent('overNodes', { - nodes: newOverNodes, - captor: e.data - }); - if (newOutNodes.length) - self.dispatchEvent('outNodes', { - nodes: newOutNodes, - captor: e.data - }); - - // Check newly overred edges: - for (i = 0; i < le; i++) { - edge = edges[i]; - currentOverEdges[edge.id] = edge; - if (!overEdges[edge.id]) { - newOverEdges.push(edge); - overEdges[edge.id] = edge; - } - } - - // Check no more overred edges: - for (k in overEdges) - if (!currentOverEdges[k]) { - newOutEdges.push(overEdges[k]); - delete overEdges[k]; - } - - // Dispatch both single and multi events: - for (i = 0, le = newOverEdges.length; i < le; i++) - self.dispatchEvent('overEdge', { - edge: newOverEdges[i], - captor: e.data - }); - for (i = 0, le = newOutEdges.length; i < le; i++) - self.dispatchEvent('outEdge', { - edge: newOutEdges[i], - captor: e.data - }); - if (newOverEdges.length) - self.dispatchEvent('overEdges', { - edges: newOverEdges, - captor: e.data - }); - if (newOutEdges.length) - self.dispatchEvent('outEdges', { - edges: newOutEdges, - captor: e.data - }); - } - - // Bind events: - captor.bind('click', onClick); - captor.bind('mousedown', onMove); - captor.bind('mouseup', onMove); - captor.bind('mousemove', onMove); - captor.bind('mouseout', onOut); - captor.bind('doubleclick', onDoubleClick); - captor.bind('rightclick', onRightClick); - self.bind('render', onMove); - } - - for (i = 0, l = this.captors.length; i < l; i++) - bindCaptor(this.captors[i]); - }; -}).call(this); diff --git a/src/demo/static/sigmajs/misc/sigma.misc.drawHovers.js b/src/demo/static/sigmajs/misc/sigma.misc.drawHovers.js deleted file mode 100644 index fa95c4195..000000000 --- a/src/demo/static/sigmajs/misc/sigma.misc.drawHovers.js +++ /dev/null @@ -1,220 +0,0 @@ -;(function(undefined) { - 'use strict'; - - if (typeof sigma === 'undefined') - throw 'sigma is not declared'; - - // Initialize packages: - sigma.utils.pkg('sigma.misc'); - - /** - * This method listens to "overNode", "outNode", "overEdge" and "outEdge" - * events from a renderer and renders the nodes differently on the top layer. - * The goal is to make any node label readable with the mouse, and to - * highlight hovered nodes and edges. - * - * It has to be called in the scope of the related renderer. - */ - sigma.misc.drawHovers = function(prefix) { - var self = this, - hoveredNodes = {}, - hoveredEdges = {}; - - this.bind('overNode', function(event) { - var node = event.data.node; - if (!node.hidden) { - hoveredNodes[node.id] = node; - draw(); - } - }); - - this.bind('outNode', function(event) { - delete hoveredNodes[event.data.node.id]; - draw(); - }); - - this.bind('overEdge', function(event) { - var edge = event.data.edge; - if (!edge.hidden) { - hoveredEdges[edge.id] = edge; - draw(); - } - }); - - this.bind('outEdge', function(event) { - delete hoveredEdges[event.data.edge.id]; - draw(); - }); - - this.bind('render', function(event) { - draw(); - }); - - function draw() { - // Clear self.contexts.hover: - self.contexts.hover.canvas.width = self.contexts.hover.canvas.width; - - var k, - source, - target, - hoveredNode, - hoveredEdge, - defaultNodeType = self.settings('defaultNodeType'), - defaultEdgeType = self.settings('defaultEdgeType'), - nodeRenderers = sigma.canvas.hovers, - edgeRenderers = sigma.canvas.edgehovers, - extremitiesRenderers = sigma.canvas.extremities, - embedSettings = self.settings.embedObjects({ - prefix: prefix - }); - - // Node render: single hover - if ( - embedSettings('enableHovering') && - embedSettings('singleHover') && - Object.keys(hoveredNodes).length - ) { - hoveredNode = hoveredNodes[Object.keys(hoveredNodes)[0]]; - ( - nodeRenderers[hoveredNode.type] || - nodeRenderers[defaultNodeType] || - nodeRenderers.def - )( - hoveredNode, - self.contexts.hover, - embedSettings - ); - } - - // Node render: multiple hover - if ( - embedSettings('enableHovering') && - !embedSettings('singleHover') - ) - for (k in hoveredNodes) - ( - nodeRenderers[hoveredNodes[k].type] || - nodeRenderers[defaultNodeType] || - nodeRenderers.def - )( - hoveredNodes[k], - self.contexts.hover, - embedSettings - ); - - // Edge render: single hover - if ( - embedSettings('enableEdgeHovering') && - embedSettings('singleHover') && - Object.keys(hoveredEdges).length - ) { - hoveredEdge = hoveredEdges[Object.keys(hoveredEdges)[0]]; - source = self.graph.nodes(hoveredEdge.source); - target = self.graph.nodes(hoveredEdge.target); - - if (! hoveredEdge.hidden) { - ( - edgeRenderers[hoveredEdge.type] || - edgeRenderers[defaultEdgeType] || - edgeRenderers.def - ) ( - hoveredEdge, - source, - target, - self.contexts.hover, - embedSettings - ); - - if (embedSettings('edgeHoverExtremities')) { - ( - extremitiesRenderers[hoveredEdge.type] || - extremitiesRenderers.def - )( - hoveredEdge, - source, - target, - self.contexts.hover, - embedSettings - ); - - } else { - // Avoid edges rendered over nodes: - ( - sigma.canvas.nodes[source.type] || - sigma.canvas.nodes.def - ) ( - source, - self.contexts.hover, - embedSettings - ); - ( - sigma.canvas.nodes[target.type] || - sigma.canvas.nodes.def - ) ( - target, - self.contexts.hover, - embedSettings - ); - } - } - } - - // Edge render: multiple hover - if ( - embedSettings('enableEdgeHovering') && - !embedSettings('singleHover') - ) { - for (k in hoveredEdges) { - hoveredEdge = hoveredEdges[k]; - source = self.graph.nodes(hoveredEdge.source); - target = self.graph.nodes(hoveredEdge.target); - - if (!hoveredEdge.hidden) { - ( - edgeRenderers[hoveredEdge.type] || - edgeRenderers[defaultEdgeType] || - edgeRenderers.def - ) ( - hoveredEdge, - source, - target, - self.contexts.hover, - embedSettings - ); - - if (embedSettings('edgeHoverExtremities')) { - ( - extremitiesRenderers[hoveredEdge.type] || - extremitiesRenderers.def - )( - hoveredEdge, - source, - target, - self.contexts.hover, - embedSettings - ); - } else { - // Avoid edges rendered over nodes: - ( - sigma.canvas.nodes[source.type] || - sigma.canvas.nodes.def - ) ( - source, - self.contexts.hover, - embedSettings - ); - ( - sigma.canvas.nodes[target.type] || - sigma.canvas.nodes.def - ) ( - target, - self.contexts.hover, - embedSettings - ); - } - } - } - } - } - }; -}).call(this); diff --git a/src/demo/static/sigmajs/renderers/canvas/sigma.canvas.edgehovers.arrow.js b/src/demo/static/sigmajs/renderers/canvas/sigma.canvas.edgehovers.arrow.js deleted file mode 100644 index 1be0cc4ab..000000000 --- a/src/demo/static/sigmajs/renderers/canvas/sigma.canvas.edgehovers.arrow.js +++ /dev/null @@ -1,76 +0,0 @@ -;(function() { - 'use strict'; - - sigma.utils.pkg('sigma.canvas.edgehovers'); - - /** - * This hover renderer will display the edge with a different color or size. - * - * @param {object} edge The edge object. - * @param {object} source node The edge source node. - * @param {object} target node The edge target node. - * @param {CanvasRenderingContext2D} context The canvas context. - * @param {configurable} settings The settings function. - */ - sigma.canvas.edgehovers.arrow = - function(edge, source, target, context, settings) { - var color = edge.color, - prefix = settings('prefix') || '', - edgeColor = settings('edgeColor'), - defaultNodeColor = settings('defaultNodeColor'), - defaultEdgeColor = settings('defaultEdgeColor'), - size = edge[prefix + 'size'] || 1, - tSize = target[prefix + 'size'], - sX = source[prefix + 'x'], - sY = source[prefix + 'y'], - tX = target[prefix + 'x'], - tY = target[prefix + 'y']; - - size = (edge.hover) ? - settings('edgeHoverSizeRatio') * size : size; - var aSize = size * 2.5, - d = Math.sqrt(Math.pow(tX - sX, 2) + Math.pow(tY - sY, 2)), - aX = sX + (tX - sX) * (d - aSize - tSize) / d, - aY = sY + (tY - sY) * (d - aSize - tSize) / d, - vX = (tX - sX) * aSize / d, - vY = (tY - sY) * aSize / d; - - if (!color) - switch (edgeColor) { - case 'source': - color = source.color || defaultNodeColor; - break; - case 'target': - color = target.color || defaultNodeColor; - break; - default: - color = defaultEdgeColor; - break; - } - - if (settings('edgeHoverColor') === 'edge') { - color = edge.hover_color || color; - } else { - color = edge.hover_color || settings('defaultEdgeHoverColor') || color; - } - - context.strokeStyle = color; - context.lineWidth = size; - context.beginPath(); - context.moveTo(sX, sY); - context.lineTo( - aX, - aY - ); - context.stroke(); - - context.fillStyle = color; - context.beginPath(); - context.moveTo(aX + vX, aY + vY); - context.lineTo(aX + vY * 0.6, aY - vX * 0.6); - context.lineTo(aX - vY * 0.6, aY + vX * 0.6); - context.lineTo(aX + vX, aY + vY); - context.closePath(); - context.fill(); - }; -})(); diff --git a/src/demo/static/sigmajs/renderers/canvas/sigma.canvas.edgehovers.curve.js b/src/demo/static/sigmajs/renderers/canvas/sigma.canvas.edgehovers.curve.js deleted file mode 100644 index f79abf8ab..000000000 --- a/src/demo/static/sigmajs/renderers/canvas/sigma.canvas.edgehovers.curve.js +++ /dev/null @@ -1,64 +0,0 @@ -;(function() { - 'use strict'; - - sigma.utils.pkg('sigma.canvas.edgehovers'); - - /** - * This hover renderer will display the edge with a different color or size. - * - * @param {object} edge The edge object. - * @param {object} source node The edge source node. - * @param {object} target node The edge target node. - * @param {CanvasRenderingContext2D} context The canvas context. - * @param {configurable} settings The settings function. - */ - sigma.canvas.edgehovers.curve = - function(edge, source, target, context, settings) { - var color = edge.color, - prefix = settings('prefix') || '', - size = settings('edgeHoverSizeRatio') * (edge[prefix + 'size'] || 1), - edgeColor = settings('edgeColor'), - defaultNodeColor = settings('defaultNodeColor'), - defaultEdgeColor = settings('defaultEdgeColor'), - cp = {}, - sSize = source[prefix + 'size'], - sX = source[prefix + 'x'], - sY = source[prefix + 'y'], - tX = target[prefix + 'x'], - tY = target[prefix + 'y']; - - cp = (source.id === target.id) ? - sigma.utils.getSelfLoopControlPoints(sX, sY, sSize) : - sigma.utils.getQuadraticControlPoint(sX, sY, tX, tY); - - if (!color) - switch (edgeColor) { - case 'source': - color = source.color || defaultNodeColor; - break; - case 'target': - color = target.color || defaultNodeColor; - break; - default: - color = defaultEdgeColor; - break; - } - - if (settings('edgeHoverColor') === 'edge') { - color = edge.hover_color || color; - } else { - color = edge.hover_color || settings('defaultEdgeHoverColor') || color; - } - - context.strokeStyle = color; - context.lineWidth = size; - context.beginPath(); - context.moveTo(sX, sY); - if (source.id === target.id) { - context.bezierCurveTo(cp.x1, cp.y1, cp.x2, cp.y2, tX, tY); - } else { - context.quadraticCurveTo(cp.x, cp.y, tX, tY); - } - context.stroke(); - }; -})(); diff --git a/src/demo/static/sigmajs/renderers/canvas/sigma.canvas.edgehovers.curvedArrow.js b/src/demo/static/sigmajs/renderers/canvas/sigma.canvas.edgehovers.curvedArrow.js deleted file mode 100644 index 6a34b7748..000000000 --- a/src/demo/static/sigmajs/renderers/canvas/sigma.canvas.edgehovers.curvedArrow.js +++ /dev/null @@ -1,96 +0,0 @@ -;(function() { - 'use strict'; - - sigma.utils.pkg('sigma.canvas.edgehovers'); - - /** - * This hover renderer will display the edge with a different color or size. - * - * @param {object} edge The edge object. - * @param {object} source node The edge source node. - * @param {object} target node The edge target node. - * @param {CanvasRenderingContext2D} context The canvas context. - * @param {configurable} settings The settings function. - */ - sigma.canvas.edgehovers.curvedArrow = - function(edge, source, target, context, settings) { - var color = edge.color, - prefix = settings('prefix') || '', - edgeColor = settings('edgeColor'), - defaultNodeColor = settings('defaultNodeColor'), - defaultEdgeColor = settings('defaultEdgeColor'), - cp = {}, - size = settings('edgeHoverSizeRatio') * (edge[prefix + 'size'] || 1), - tSize = target[prefix + 'size'], - sX = source[prefix + 'x'], - sY = source[prefix + 'y'], - tX = target[prefix + 'x'], - tY = target[prefix + 'y'], - d, - aSize, - aX, - aY, - vX, - vY; - - cp = (source.id === target.id) ? - sigma.utils.getSelfLoopControlPoints(sX, sY, tSize) : - sigma.utils.getQuadraticControlPoint(sX, sY, tX, tY); - - if (source.id === target.id) { - d = Math.sqrt(Math.pow(tX - cp.x1, 2) + Math.pow(tY - cp.y1, 2)); - aSize = size * 2.5; - aX = cp.x1 + (tX - cp.x1) * (d - aSize - tSize) / d; - aY = cp.y1 + (tY - cp.y1) * (d - aSize - tSize) / d; - vX = (tX - cp.x1) * aSize / d; - vY = (tY - cp.y1) * aSize / d; - } - else { - d = Math.sqrt(Math.pow(tX - cp.x, 2) + Math.pow(tY - cp.y, 2)); - aSize = size * 2.5; - aX = cp.x + (tX - cp.x) * (d - aSize - tSize) / d; - aY = cp.y + (tY - cp.y) * (d - aSize - tSize) / d; - vX = (tX - cp.x) * aSize / d; - vY = (tY - cp.y) * aSize / d; - } - - if (!color) - switch (edgeColor) { - case 'source': - color = source.color || defaultNodeColor; - break; - case 'target': - color = target.color || defaultNodeColor; - break; - default: - color = defaultEdgeColor; - break; - } - - if (settings('edgeHoverColor') === 'edge') { - color = edge.hover_color || color; - } else { - color = edge.hover_color || settings('defaultEdgeHoverColor') || color; - } - - context.strokeStyle = color; - context.lineWidth = size; - context.beginPath(); - context.moveTo(sX, sY); - if (source.id === target.id) { - context.bezierCurveTo(cp.x2, cp.y2, cp.x1, cp.y1, aX, aY); - } else { - context.quadraticCurveTo(cp.x, cp.y, aX, aY); - } - context.stroke(); - - context.fillStyle = color; - context.beginPath(); - context.moveTo(aX + vX, aY + vY); - context.lineTo(aX + vY * 0.6, aY - vX * 0.6); - context.lineTo(aX - vY * 0.6, aY + vX * 0.6); - context.lineTo(aX + vX, aY + vY); - context.closePath(); - context.fill(); - }; -})(); diff --git a/src/demo/static/sigmajs/renderers/canvas/sigma.canvas.edgehovers.def.js b/src/demo/static/sigmajs/renderers/canvas/sigma.canvas.edgehovers.def.js deleted file mode 100644 index d88ad387f..000000000 --- a/src/demo/static/sigmajs/renderers/canvas/sigma.canvas.edgehovers.def.js +++ /dev/null @@ -1,57 +0,0 @@ -;(function() { - 'use strict'; - - sigma.utils.pkg('sigma.canvas.edgehovers'); - - /** - * This hover renderer will display the edge with a different color or size. - * - * @param {object} edge The edge object. - * @param {object} source node The edge source node. - * @param {object} target node The edge target node. - * @param {CanvasRenderingContext2D} context The canvas context. - * @param {configurable} settings The settings function. - */ - sigma.canvas.edgehovers.def = - function(edge, source, target, context, settings) { - var color = edge.color, - prefix = settings('prefix') || '', - size = edge[prefix + 'size'] || 1, - edgeColor = settings('edgeColor'), - defaultNodeColor = settings('defaultNodeColor'), - defaultEdgeColor = settings('defaultEdgeColor'); - - if (!color) - switch (edgeColor) { - case 'source': - color = source.color || defaultNodeColor; - break; - case 'target': - color = target.color || defaultNodeColor; - break; - default: - color = defaultEdgeColor; - break; - } - - if (settings('edgeHoverColor') === 'edge') { - color = edge.hover_color || color; - } else { - color = edge.hover_color || settings('defaultEdgeHoverColor') || color; - } - size *= settings('edgeHoverSizeRatio'); - - context.strokeStyle = color; - context.lineWidth = size; - context.beginPath(); - context.moveTo( - source[prefix + 'x'], - source[prefix + 'y'] - ); - context.lineTo( - target[prefix + 'x'], - target[prefix + 'y'] - ); - context.stroke(); - }; -})(); diff --git a/src/demo/static/sigmajs/renderers/canvas/sigma.canvas.edges.arrow.js b/src/demo/static/sigmajs/renderers/canvas/sigma.canvas.edges.arrow.js deleted file mode 100644 index 4f12977a8..000000000 --- a/src/demo/static/sigmajs/renderers/canvas/sigma.canvas.edges.arrow.js +++ /dev/null @@ -1,66 +0,0 @@ -;(function() { - 'use strict'; - - sigma.utils.pkg('sigma.canvas.edges'); - - /** - * This edge renderer will display edges as arrows going from the source node - * - * @param {object} edge The edge object. - * @param {object} source node The edge source node. - * @param {object} target node The edge target node. - * @param {CanvasRenderingContext2D} context The canvas context. - * @param {configurable} settings The settings function. - */ - sigma.canvas.edges.arrow = function(edge, source, target, context, settings) { - var color = edge.color, - prefix = settings('prefix') || '', - edgeColor = settings('edgeColor'), - defaultNodeColor = settings('defaultNodeColor'), - defaultEdgeColor = settings('defaultEdgeColor'), - size = edge[prefix + 'size'] || 1, - tSize = target[prefix + 'size'], - sX = source[prefix + 'x'], - sY = source[prefix + 'y'], - tX = target[prefix + 'x'], - tY = target[prefix + 'y'], - aSize = Math.max(size * 2.5, settings('minArrowSize')), - d = Math.sqrt(Math.pow(tX - sX, 2) + Math.pow(tY - sY, 2)), - aX = sX + (tX - sX) * (d - aSize - tSize) / d, - aY = sY + (tY - sY) * (d - aSize - tSize) / d, - vX = (tX - sX) * aSize / d, - vY = (tY - sY) * aSize / d; - - if (!color) - switch (edgeColor) { - case 'source': - color = source.color || defaultNodeColor; - break; - case 'target': - color = target.color || defaultNodeColor; - break; - default: - color = defaultEdgeColor; - break; - } - - context.strokeStyle = color; - context.lineWidth = size; - context.beginPath(); - context.moveTo(sX, sY); - context.lineTo( - aX, - aY - ); - context.stroke(); - - context.fillStyle = color; - context.beginPath(); - context.moveTo(aX + vX, aY + vY); - context.lineTo(aX + vY * 0.6, aY - vX * 0.6); - context.lineTo(aX - vY * 0.6, aY + vX * 0.6); - context.lineTo(aX + vX, aY + vY); - context.closePath(); - context.fill(); - }; -})(); diff --git a/src/demo/static/sigmajs/renderers/canvas/sigma.canvas.edges.curve.js b/src/demo/static/sigmajs/renderers/canvas/sigma.canvas.edges.curve.js deleted file mode 100644 index 3e1502b4f..000000000 --- a/src/demo/static/sigmajs/renderers/canvas/sigma.canvas.edges.curve.js +++ /dev/null @@ -1,57 +0,0 @@ -;(function() { - 'use strict'; - - sigma.utils.pkg('sigma.canvas.edges'); - - /** - * This edge renderer will display edges as curves. - * - * @param {object} edge The edge object. - * @param {object} source node The edge source node. - * @param {object} target node The edge target node. - * @param {CanvasRenderingContext2D} context The canvas context. - * @param {configurable} settings The settings function. - */ - sigma.canvas.edges.curve = function(edge, source, target, context, settings) { - var color = edge.color, - prefix = settings('prefix') || '', - size = edge[prefix + 'size'] || 1, - edgeColor = settings('edgeColor'), - defaultNodeColor = settings('defaultNodeColor'), - defaultEdgeColor = settings('defaultEdgeColor'), - cp = {}, - sSize = source[prefix + 'size'], - sX = source[prefix + 'x'], - sY = source[prefix + 'y'], - tX = target[prefix + 'x'], - tY = target[prefix + 'y']; - - cp = (source.id === target.id) ? - sigma.utils.getSelfLoopControlPoints(sX, sY, sSize) : - sigma.utils.getQuadraticControlPoint(sX, sY, tX, tY); - - if (!color) - switch (edgeColor) { - case 'source': - color = source.color || defaultNodeColor; - break; - case 'target': - color = target.color || defaultNodeColor; - break; - default: - color = defaultEdgeColor; - break; - } - - context.strokeStyle = color; - context.lineWidth = size; - context.beginPath(); - context.moveTo(sX, sY); - if (source.id === target.id) { - context.bezierCurveTo(cp.x1, cp.y1, cp.x2, cp.y2, tX, tY); - } else { - context.quadraticCurveTo(cp.x, cp.y, tX, tY); - } - context.stroke(); - }; -})(); diff --git a/src/demo/static/sigmajs/renderers/canvas/sigma.canvas.edges.curvedArrow.js b/src/demo/static/sigmajs/renderers/canvas/sigma.canvas.edges.curvedArrow.js deleted file mode 100644 index 9c7b66383..000000000 --- a/src/demo/static/sigmajs/renderers/canvas/sigma.canvas.edges.curvedArrow.js +++ /dev/null @@ -1,88 +0,0 @@ -;(function() { - 'use strict'; - - sigma.utils.pkg('sigma.canvas.edges'); - - /** - * This edge renderer will display edges as curves with arrow heading. - * - * @param {object} edge The edge object. - * @param {object} source node The edge source node. - * @param {object} target node The edge target node. - * @param {CanvasRenderingContext2D} context The canvas context. - * @param {configurable} settings The settings function. - */ - sigma.canvas.edges.curvedArrow = - function(edge, source, target, context, settings) { - var color = edge.color, - prefix = settings('prefix') || '', - edgeColor = settings('edgeColor'), - defaultNodeColor = settings('defaultNodeColor'), - defaultEdgeColor = settings('defaultEdgeColor'), - cp = {}, - size = edge[prefix + 'size'] || 1, - tSize = target[prefix + 'size'], - sX = source[prefix + 'x'], - sY = source[prefix + 'y'], - tX = target[prefix + 'x'], - tY = target[prefix + 'y'], - aSize = Math.max(size * 2.5, settings('minArrowSize')), - d, - aX, - aY, - vX, - vY; - - cp = (source.id === target.id) ? - sigma.utils.getSelfLoopControlPoints(sX, sY, tSize) : - sigma.utils.getQuadraticControlPoint(sX, sY, tX, tY); - - if (source.id === target.id) { - d = Math.sqrt(Math.pow(tX - cp.x1, 2) + Math.pow(tY - cp.y1, 2)); - aX = cp.x1 + (tX - cp.x1) * (d - aSize - tSize) / d; - aY = cp.y1 + (tY - cp.y1) * (d - aSize - tSize) / d; - vX = (tX - cp.x1) * aSize / d; - vY = (tY - cp.y1) * aSize / d; - } - else { - d = Math.sqrt(Math.pow(tX - cp.x, 2) + Math.pow(tY - cp.y, 2)); - aX = cp.x + (tX - cp.x) * (d - aSize - tSize) / d; - aY = cp.y + (tY - cp.y) * (d - aSize - tSize) / d; - vX = (tX - cp.x) * aSize / d; - vY = (tY - cp.y) * aSize / d; - } - - if (!color) - switch (edgeColor) { - case 'source': - color = source.color || defaultNodeColor; - break; - case 'target': - color = target.color || defaultNodeColor; - break; - default: - color = defaultEdgeColor; - break; - } - - context.strokeStyle = color; - context.lineWidth = size; - context.beginPath(); - context.moveTo(sX, sY); - if (source.id === target.id) { - context.bezierCurveTo(cp.x2, cp.y2, cp.x1, cp.y1, aX, aY); - } else { - context.quadraticCurveTo(cp.x, cp.y, aX, aY); - } - context.stroke(); - - context.fillStyle = color; - context.beginPath(); - context.moveTo(aX + vX, aY + vY); - context.lineTo(aX + vY * 0.6, aY - vX * 0.6); - context.lineTo(aX - vY * 0.6, aY + vX * 0.6); - context.lineTo(aX + vX, aY + vY); - context.closePath(); - context.fill(); - }; -})(); diff --git a/src/demo/static/sigmajs/renderers/canvas/sigma.canvas.edges.def.js b/src/demo/static/sigmajs/renderers/canvas/sigma.canvas.edges.def.js deleted file mode 100644 index dd97b9037..000000000 --- a/src/demo/static/sigmajs/renderers/canvas/sigma.canvas.edges.def.js +++ /dev/null @@ -1,49 +0,0 @@ -;(function() { - 'use strict'; - - sigma.utils.pkg('sigma.canvas.edges'); - - /** - * The default edge renderer. It renders the edge as a simple line. - * - * @param {object} edge The edge object. - * @param {object} source node The edge source node. - * @param {object} target node The edge target node. - * @param {CanvasRenderingContext2D} context The canvas context. - * @param {configurable} settings The settings function. - */ - sigma.canvas.edges.def = function(edge, source, target, context, settings) { - var color = edge.color, - prefix = settings('prefix') || '', - size = edge[prefix + 'size'] || 1, - edgeColor = settings('edgeColor'), - defaultNodeColor = settings('defaultNodeColor'), - defaultEdgeColor = settings('defaultEdgeColor'); - - if (!color) - switch (edgeColor) { - case 'source': - color = source.color || defaultNodeColor; - break; - case 'target': - color = target.color || defaultNodeColor; - break; - default: - color = defaultEdgeColor; - break; - } - - context.strokeStyle = color; - context.lineWidth = size; - context.beginPath(); - context.moveTo( - source[prefix + 'x'], - source[prefix + 'y'] - ); - context.lineTo( - target[prefix + 'x'], - target[prefix + 'y'] - ); - context.stroke(); - }; -})(); diff --git a/src/demo/static/sigmajs/renderers/canvas/sigma.canvas.extremities.def.js b/src/demo/static/sigmajs/renderers/canvas/sigma.canvas.extremities.def.js deleted file mode 100644 index 7877dc2ca..000000000 --- a/src/demo/static/sigmajs/renderers/canvas/sigma.canvas.extremities.def.js +++ /dev/null @@ -1,38 +0,0 @@ -;(function(undefined) { - 'use strict'; - - if (typeof sigma === 'undefined') - throw 'sigma is not declared'; - - // Initialize packages: - sigma.utils.pkg('sigma.canvas.extremities'); - - /** - * The default renderer for hovered edge extremities. It renders the edge - * extremities as hovered. - * - * @param {object} edge The edge object. - * @param {object} source node The edge source node. - * @param {object} target node The edge target node. - * @param {CanvasRenderingContext2D} context The canvas context. - * @param {configurable} settings The settings function. - */ - sigma.canvas.extremities.def = - function(edge, source, target, context, settings) { - // Source Node: - ( - sigma.canvas.hovers[source.type] || - sigma.canvas.hovers.def - ) ( - source, context, settings - ); - - // Target Node: - ( - sigma.canvas.hovers[target.type] || - sigma.canvas.hovers.def - ) ( - target, context, settings - ); - }; -}).call(this); diff --git a/src/demo/static/sigmajs/renderers/canvas/sigma.canvas.hovers.def.js b/src/demo/static/sigmajs/renderers/canvas/sigma.canvas.hovers.def.js deleted file mode 100644 index 00185c251..000000000 --- a/src/demo/static/sigmajs/renderers/canvas/sigma.canvas.hovers.def.js +++ /dev/null @@ -1,106 +0,0 @@ -;(function(undefined) { - 'use strict'; - - if (typeof sigma === 'undefined') - throw 'sigma is not declared'; - - // Initialize packages: - sigma.utils.pkg('sigma.canvas.hovers'); - - /** - * This hover renderer will basically display the label with a background. - * - * @param {object} node The node object. - * @param {CanvasRenderingContext2D} context The canvas context. - * @param {configurable} settings The settings function. - */ - sigma.canvas.hovers.def = function(node, context, settings) { - var x, - y, - w, - h, - e, - fontStyle = settings('hoverFontStyle') || settings('fontStyle'), - prefix = settings('prefix') || '', - size = node[prefix + 'size'], - fontSize = (settings('labelSize') === 'fixed') ? - settings('defaultLabelSize') : - settings('labelSizeRatio') * size; - - // Label background: - context.font = (fontStyle ? fontStyle + ' ' : '') + - fontSize + 'px ' + (settings('hoverFont') || settings('font')); - - context.beginPath(); - context.fillStyle = settings('labelHoverBGColor') === 'node' ? - (node.color || settings('defaultNodeColor')) : - settings('defaultHoverLabelBGColor'); - - if (node.label && settings('labelHoverShadow')) { - context.shadowOffsetX = 0; - context.shadowOffsetY = 0; - context.shadowBlur = 8; - context.shadowColor = settings('labelHoverShadowColor'); - } - - if (node.label && typeof node.label === 'string') { - x = Math.round(node[prefix + 'x'] - fontSize / 2 - 2); - y = Math.round(node[prefix + 'y'] - fontSize / 2 - 2); - w = Math.round( - context.measureText(node.label).width + fontSize / 2 + size + 7 - ); - h = Math.round(fontSize + 4); - e = Math.round(fontSize / 2 + 2); - - context.moveTo(x, y + e); - context.arcTo(x, y, x + e, y, e); - context.lineTo(x + w, y); - context.lineTo(x + w, y + h); - context.lineTo(x + e, y + h); - context.arcTo(x, y + h, x, y + h - e, e); - context.lineTo(x, y + e); - - context.closePath(); - context.fill(); - - context.shadowOffsetX = 0; - context.shadowOffsetY = 0; - context.shadowBlur = 0; - } - - // Node border: - if (settings('borderSize') > 0) { - context.beginPath(); - context.fillStyle = settings('nodeBorderColor') === 'node' ? - (node.color || settings('defaultNodeColor')) : - settings('defaultNodeBorderColor'); - context.arc( - node[prefix + 'x'], - node[prefix + 'y'], - size + settings('borderSize'), - 0, - Math.PI * 2, - true - ); - context.closePath(); - context.fill(); - } - - // Node: - var nodeRenderer = sigma.canvas.nodes[node.type] || sigma.canvas.nodes.def; - nodeRenderer(node, context, settings); - - // Display the label: - if (node.label && typeof node.label === 'string') { - context.fillStyle = (settings('labelHoverColor') === 'node') ? - (node.color || settings('defaultNodeColor')) : - settings('defaultLabelHoverColor'); - - context.fillText( - node.label, - Math.round(node[prefix + 'x'] + size + 3), - Math.round(node[prefix + 'y'] + fontSize / 3) - ); - } - }; -}).call(this); diff --git a/src/demo/static/sigmajs/renderers/canvas/sigma.canvas.labels.def.js b/src/demo/static/sigmajs/renderers/canvas/sigma.canvas.labels.def.js deleted file mode 100644 index 8a70d7390..000000000 --- a/src/demo/static/sigmajs/renderers/canvas/sigma.canvas.labels.def.js +++ /dev/null @@ -1,44 +0,0 @@ -;(function(undefined) { - 'use strict'; - - if (typeof sigma === 'undefined') - throw 'sigma is not declared'; - - // Initialize packages: - sigma.utils.pkg('sigma.canvas.labels'); - - /** - * This label renderer will just display the label on the right of the node. - * - * @param {object} node The node object. - * @param {CanvasRenderingContext2D} context The canvas context. - * @param {configurable} settings The settings function. - */ - sigma.canvas.labels.def = function(node, context, settings) { - var fontSize, - prefix = settings('prefix') || '', - size = node[prefix + 'size']; - - if (size < settings('labelThreshold')) - return; - - if (!node.label || typeof node.label !== 'string') - return; - - fontSize = (settings('labelSize') === 'fixed') ? - settings('defaultLabelSize') : - settings('labelSizeRatio') * size; - - context.font = (settings('fontStyle') ? settings('fontStyle') + ' ' : '') + - fontSize + 'px ' + settings('font'); - context.fillStyle = (settings('labelColor') === 'node') ? - (node.color || settings('defaultNodeColor')) : - settings('defaultLabelColor'); - - context.fillText( - node.label, - Math.round(node[prefix + 'x'] + size + 3), - Math.round(node[prefix + 'y'] + fontSize / 3) - ); - }; -}).call(this); diff --git a/src/demo/static/sigmajs/renderers/canvas/sigma.canvas.nodes.def.js b/src/demo/static/sigmajs/renderers/canvas/sigma.canvas.nodes.def.js deleted file mode 100644 index ee499b005..000000000 --- a/src/demo/static/sigmajs/renderers/canvas/sigma.canvas.nodes.def.js +++ /dev/null @@ -1,30 +0,0 @@ -;(function() { - 'use strict'; - - sigma.utils.pkg('sigma.canvas.nodes'); - - /** - * The default node renderer. It renders the node as a simple disc. - * - * @param {object} node The node object. - * @param {CanvasRenderingContext2D} context The canvas context. - * @param {configurable} settings The settings function. - */ - sigma.canvas.nodes.def = function(node, context, settings) { - var prefix = settings('prefix') || ''; - - context.fillStyle = node.color || settings('defaultNodeColor'); - context.beginPath(); - context.arc( - node[prefix + 'x'], - node[prefix + 'y'], - node[prefix + 'size'], - 0, - Math.PI * 2, - true - ); - - context.closePath(); - context.fill(); - }; -})(); diff --git a/src/demo/static/sigmajs/renderers/sigma.renderers.canvas.js b/src/demo/static/sigmajs/renderers/sigma.renderers.canvas.js deleted file mode 100644 index 4eda14550..000000000 --- a/src/demo/static/sigmajs/renderers/sigma.renderers.canvas.js +++ /dev/null @@ -1,450 +0,0 @@ -;(function(undefined) { - 'use strict'; - - if (typeof sigma === 'undefined') - throw 'sigma is not declared'; - - if (typeof conrad === 'undefined') - throw 'conrad is not declared'; - - // Initialize packages: - sigma.utils.pkg('sigma.renderers'); - - /** - * This function is the constructor of the canvas sigma's renderer. - * - * @param {sigma.classes.graph} graph The graph to render. - * @param {sigma.classes.camera} camera The camera. - * @param {configurable} settings The sigma instance settings - * function. - * @param {object} object The options object. - * @return {sigma.renderers.canvas} The renderer instance. - */ - sigma.renderers.canvas = function(graph, camera, settings, options) { - if (typeof options !== 'object') - throw 'sigma.renderers.canvas: Wrong arguments.'; - - if (!(options.container instanceof HTMLElement)) - throw 'Container not found.'; - - var k, - i, - l, - a, - fn, - self = this; - - sigma.classes.dispatcher.extend(this); - - // Initialize main attributes: - Object.defineProperty(this, 'conradId', { - value: sigma.utils.id() - }); - this.graph = graph; - this.camera = camera; - this.contexts = {}; - this.domElements = {}; - this.options = options; - this.container = this.options.container; - this.settings = ( - typeof options.settings === 'object' && - options.settings - ) ? - settings.embedObjects(options.settings) : - settings; - - // Node indexes: - this.nodesOnScreen = []; - this.edgesOnScreen = []; - - // Conrad related attributes: - this.jobs = {}; - - // Find the prefix: - this.options.prefix = 'renderer' + this.conradId + ':'; - - // Initialize the DOM elements: - if ( - !this.settings('batchEdgesDrawing') - ) { - this.initDOM('canvas', 'scene'); - this.contexts.edges = this.contexts.scene; - this.contexts.nodes = this.contexts.scene; - this.contexts.labels = this.contexts.scene; - } else { - this.initDOM('canvas', 'edges'); - this.initDOM('canvas', 'scene'); - this.contexts.nodes = this.contexts.scene; - this.contexts.labels = this.contexts.scene; - } - - this.initDOM('canvas', 'mouse'); - this.contexts.hover = this.contexts.mouse; - - // Initialize captors: - this.captors = []; - a = this.options.captors || [sigma.captors.mouse, sigma.captors.touch]; - for (i = 0, l = a.length; i < l; i++) { - fn = typeof a[i] === 'function' ? a[i] : sigma.captors[a[i]]; - this.captors.push( - new fn( - this.domElements.mouse, - this.camera, - this.settings - ) - ); - } - - // Deal with sigma events: - sigma.misc.bindEvents.call(this, this.options.prefix); - sigma.misc.drawHovers.call(this, this.options.prefix); - - this.resize(false); - }; - - - - - /** - * This method renders the graph on the canvases. - * - * @param {?object} options Eventually an object of options. - * @return {sigma.renderers.canvas} Returns the instance itself. - */ - sigma.renderers.canvas.prototype.render = function(options) { - options = options || {}; - - var a, - i, - k, - l, - o, - id, - end, - job, - start, - edges, - renderers, - rendererType, - batchSize, - tempGCO, - index = {}, - graph = this.graph, - nodes = this.graph.nodes, - prefix = this.options.prefix || '', - drawEdges = this.settings(options, 'drawEdges'), - drawNodes = this.settings(options, 'drawNodes'), - drawLabels = this.settings(options, 'drawLabels'), - drawEdgeLabels = this.settings(options, 'drawEdgeLabels'), - embedSettings = this.settings.embedObjects(options, { - prefix: this.options.prefix - }); - - // Call the resize function: - this.resize(false); - - // Check the 'hideEdgesOnMove' setting: - if (this.settings(options, 'hideEdgesOnMove')) - if (this.camera.isAnimated || this.camera.isMoving) - drawEdges = false; - - // Apply the camera's view: - this.camera.applyView( - undefined, - this.options.prefix, - { - width: this.width, - height: this.height - } - ); - - // Clear canvases: - this.clear(); - - // Kill running jobs: - for (k in this.jobs) - if (conrad.hasJob(k)) - conrad.killJob(k); - - // Find which nodes are on screen: - this.edgesOnScreen = []; - this.nodesOnScreen = this.camera.quadtree.area( - this.camera.getRectangle(this.width, this.height) - ); - - for (a = this.nodesOnScreen, i = 0, l = a.length; i < l; i++) - index[a[i].id] = a[i]; - - // Draw edges: - // - If settings('batchEdgesDrawing') is true, the edges are displayed per - // batches. If not, they are drawn in one frame. - if (drawEdges) { - // First, let's identify which edges to draw. To do this, we just keep - // every edges that have at least one extremity displayed according to - // the quadtree and the "hidden" attribute. We also do not keep hidden - // edges. - for (a = graph.edges(), i = 0, l = a.length; i < l; i++) { - o = a[i]; - if ( - (index[o.source] || index[o.target]) && - (!o.hidden && !nodes(o.source).hidden && !nodes(o.target).hidden) - ) - this.edgesOnScreen.push(o); - } - - // If the "batchEdgesDrawing" settings is true, edges are batched: - if (this.settings(options, 'batchEdgesDrawing')) { - id = 'edges_' + this.conradId; - batchSize = embedSettings('canvasEdgesBatchSize'); - - edges = this.edgesOnScreen; - l = edges.length; - - start = 0; - end = Math.min(edges.length, start + batchSize); - - job = function() { - tempGCO = this.contexts.edges.globalCompositeOperation; - this.contexts.edges.globalCompositeOperation = 'destination-over'; - - renderers = sigma.canvas.edges; - for (i = start; i < end; i++) { - o = edges[i]; - (renderers[ - o.type || this.settings(options, 'defaultEdgeType') - ] || renderers.def)( - o, - graph.nodes(o.source), - graph.nodes(o.target), - this.contexts.edges, - embedSettings - ); - } - - // Draw edge labels: - if (drawEdgeLabels) { - renderers = sigma.canvas.edges.labels; - for (i = start; i < end; i++) { - o = edges[i]; - if (!o.hidden) - (renderers[ - o.type || this.settings(options, 'defaultEdgeType') - ] || renderers.def)( - o, - graph.nodes(o.source), - graph.nodes(o.target), - this.contexts.labels, - embedSettings - ); - } - } - - // Restore original globalCompositeOperation: - this.contexts.edges.globalCompositeOperation = tempGCO; - - // Catch job's end: - if (end === edges.length) { - delete this.jobs[id]; - return false; - } - - start = end + 1; - end = Math.min(edges.length, start + batchSize); - return true; - }; - - this.jobs[id] = job; - conrad.addJob(id, job.bind(this)); - - // If not, they are drawn in one frame: - } else { - renderers = sigma.canvas.edges; - for (a = this.edgesOnScreen, i = 0, l = a.length; i < l; i++) { - o = a[i]; - (renderers[ - o.type || this.settings(options, 'defaultEdgeType') - ] || renderers.def)( - o, - graph.nodes(o.source), - graph.nodes(o.target), - this.contexts.edges, - embedSettings - ); - } - - // Draw edge labels: - // - No batching - if (drawEdgeLabels) { - renderers = sigma.canvas.edges.labels; - for (a = this.edgesOnScreen, i = 0, l = a.length; i < l; i++) - if (!a[i].hidden) - (renderers[ - a[i].type || this.settings(options, 'defaultEdgeType') - ] || renderers.def)( - a[i], - graph.nodes(a[i].source), - graph.nodes(a[i].target), - this.contexts.labels, - embedSettings - ); - } - } - } - - // Draw nodes: - // - No batching - if (drawNodes) { - renderers = sigma.canvas.nodes; - for (a = this.nodesOnScreen, i = 0, l = a.length; i < l; i++) - if (!a[i].hidden) - (renderers[ - a[i].type || this.settings(options, 'defaultNodeType') - ] || renderers.def)( - a[i], - this.contexts.nodes, - embedSettings - ); - } - - // Draw labels: - // - No batching - if (drawLabels) { - renderers = sigma.canvas.labels; - for (a = this.nodesOnScreen, i = 0, l = a.length; i < l; i++) - if (!a[i].hidden) - (renderers[ - a[i].type || this.settings(options, 'defaultNodeType') - ] || renderers.def)( - a[i], - this.contexts.labels, - embedSettings - ); - } - - this.dispatchEvent('render'); - - return this; - }; - - /** - * This method creates a DOM element of the specified type, switches its - * position to "absolute", references it to the domElements attribute, and - * finally appends it to the container. - * - * @param {string} tag The label tag. - * @param {string} id The id of the element (to store it in "domElements"). - */ - sigma.renderers.canvas.prototype.initDOM = function(tag, id) { - var dom = document.createElement(tag); - - dom.style.position = 'absolute'; - dom.setAttribute('class', 'sigma-' + id); - - this.domElements[id] = dom; - this.container.appendChild(dom); - - if (tag.toLowerCase() === 'canvas') - this.contexts[id] = dom.getContext('2d'); - }; - - /** - * This method resizes each DOM elements in the container and stores the new - * dimensions. Then, it renders the graph. - * - * @param {?number} width The new width of the container. - * @param {?number} height The new height of the container. - * @return {sigma.renderers.canvas} Returns the instance itself. - */ - sigma.renderers.canvas.prototype.resize = function(w, h) { - var k, - oldWidth = this.width, - oldHeight = this.height, - pixelRatio = 1; - // TODO: - // ***** - // This pixelRatio is the solution to display with the good definition - // on canvases on Retina displays (ie oversampling). Unfortunately, it - // has a huge performance cost... - // > pixelRatio = window.devicePixelRatio || 1; - - if (w !== undefined && h !== undefined) { - this.width = w; - this.height = h; - } else { - this.width = this.container.offsetWidth; - this.height = this.container.offsetHeight; - - w = this.width; - h = this.height; - } - - if (oldWidth !== this.width || oldHeight !== this.height) { - for (k in this.domElements) { - this.domElements[k].style.width = w + 'px'; - this.domElements[k].style.height = h + 'px'; - - if (this.domElements[k].tagName.toLowerCase() === 'canvas') { - this.domElements[k].setAttribute('width', (w * pixelRatio) + 'px'); - this.domElements[k].setAttribute('height', (h * pixelRatio) + 'px'); - - if (pixelRatio !== 1) - this.contexts[k].scale(pixelRatio, pixelRatio); - } - } - } - - return this; - }; - - /** - * This method clears each canvas. - * - * @return {sigma.renderers.canvas} Returns the instance itself. - */ - sigma.renderers.canvas.prototype.clear = function() { - var k; - - for (k in this.domElements) - if (this.domElements[k].tagName === 'CANVAS') - this.domElements[k].width = this.domElements[k].width; - - return this; - }; - - /** - * This method kills contexts and other attributes. - */ - sigma.renderers.canvas.prototype.kill = function() { - var k, - captor; - - // Kill captors: - while ((captor = this.captors.pop())) - captor.kill(); - delete this.captors; - - // Kill contexts: - for (k in this.domElements) { - this.domElements[k].parentNode.removeChild(this.domElements[k]); - delete this.domElements[k]; - delete this.contexts[k]; - } - delete this.domElements; - delete this.contexts; - }; - - - - - /** - * The labels, nodes and edges renderers are stored in the three following - * objects. When an element is drawn, its type will be checked and if a - * renderer with the same name exists, it will be used. If not found, the - * default renderer will be used instead. - * - * They are stored in different files, in the "./canvas" folder. - */ - sigma.utils.pkg('sigma.canvas.nodes'); - sigma.utils.pkg('sigma.canvas.edges'); - sigma.utils.pkg('sigma.canvas.labels'); -}).call(this); diff --git a/src/demo/static/sigmajs/renderers/sigma.renderers.def.js b/src/demo/static/sigmajs/renderers/sigma.renderers.def.js deleted file mode 100644 index b091d39da..000000000 --- a/src/demo/static/sigmajs/renderers/sigma.renderers.def.js +++ /dev/null @@ -1,29 +0,0 @@ -;(function(global) { - 'use strict'; - - if (typeof sigma === 'undefined') - throw 'sigma is not declared'; - - // Initialize packages: - sigma.utils.pkg('sigma.renderers'); - - // Check if WebGL is enabled: - var canvas, - webgl = !!global.WebGLRenderingContext; - if (webgl) { - canvas = document.createElement('canvas'); - try { - webgl = !!( - canvas.getContext('webgl') || - canvas.getContext('experimental-webgl') - ); - } catch (e) { - webgl = false; - } - } - - // Copy the good renderer: - sigma.renderers.def = webgl ? - sigma.renderers.webgl : - sigma.renderers.canvas; -})(this); diff --git a/src/demo/static/sigmajs/renderers/sigma.renderers.svg.js b/src/demo/static/sigmajs/renderers/sigma.renderers.svg.js deleted file mode 100644 index ffec79e00..000000000 --- a/src/demo/static/sigmajs/renderers/sigma.renderers.svg.js +++ /dev/null @@ -1,479 +0,0 @@ -;(function(undefined) { - 'use strict'; - - if (typeof sigma === 'undefined') - throw 'sigma is not declared'; - - if (typeof conrad === 'undefined') - throw 'conrad is not declared'; - - // Initialize packages: - sigma.utils.pkg('sigma.renderers'); - - /** - * This function is the constructor of the svg sigma's renderer. - * - * @param {sigma.classes.graph} graph The graph to render. - * @param {sigma.classes.camera} camera The camera. - * @param {configurable} settings The sigma instance settings - * function. - * @param {object} object The options object. - * @return {sigma.renderers.svg} The renderer instance. - */ - sigma.renderers.svg = function(graph, camera, settings, options) { - if (typeof options !== 'object') - throw 'sigma.renderers.svg: Wrong arguments.'; - - if (!(options.container instanceof HTMLElement)) - throw 'Container not found.'; - - var i, - l, - a, - fn, - self = this; - - sigma.classes.dispatcher.extend(this); - - // Initialize main attributes: - this.graph = graph; - this.camera = camera; - this.domElements = { - graph: null, - groups: {}, - nodes: {}, - edges: {}, - labels: {}, - hovers: {} - }; - this.measurementCanvas = null; - this.options = options; - this.container = this.options.container; - this.settings = ( - typeof options.settings === 'object' && - options.settings - ) ? - settings.embedObjects(options.settings) : - settings; - - // Is the renderer meant to be freestyle? - this.settings('freeStyle', !!this.options.freeStyle); - - // SVG xmlns - this.settings('xmlns', 'http://www.w3.org/2000/svg'); - - // Indexes: - this.nodesOnScreen = []; - this.edgesOnScreen = []; - - // Find the prefix: - this.options.prefix = 'renderer' + sigma.utils.id() + ':'; - - // Initialize the DOM elements - this.initDOM('svg'); - - // Initialize captors: - this.captors = []; - a = this.options.captors || [sigma.captors.mouse, sigma.captors.touch]; - for (i = 0, l = a.length; i < l; i++) { - fn = typeof a[i] === 'function' ? a[i] : sigma.captors[a[i]]; - this.captors.push( - new fn( - this.domElements.graph, - this.camera, - this.settings - ) - ); - } - - // Bind resize: - window.addEventListener('resize', function() { - self.resize(); - }); - - // Deal with sigma events: - // TODO: keep an option to override the DOM events? - sigma.misc.bindDOMEvents.call(this, this.domElements.graph); - this.bindHovers(this.options.prefix); - - // Resize - this.resize(false); - }; - - /** - * This method renders the graph on the svg scene. - * - * @param {?object} options Eventually an object of options. - * @return {sigma.renderers.svg} Returns the instance itself. - */ - sigma.renderers.svg.prototype.render = function(options) { - options = options || {}; - - var a, - i, - k, - e, - l, - o, - source, - target, - start, - edges, - renderers, - subrenderers, - index = {}, - graph = this.graph, - nodes = this.graph.nodes, - prefix = this.options.prefix || '', - drawEdges = this.settings(options, 'drawEdges'), - drawNodes = this.settings(options, 'drawNodes'), - drawLabels = this.settings(options, 'drawLabels'), - embedSettings = this.settings.embedObjects(options, { - prefix: this.options.prefix, - forceLabels: this.options.forceLabels - }); - - // Check the 'hideEdgesOnMove' setting: - if (this.settings(options, 'hideEdgesOnMove')) - if (this.camera.isAnimated || this.camera.isMoving) - drawEdges = false; - - // Apply the camera's view: - this.camera.applyView( - undefined, - this.options.prefix, - { - width: this.width, - height: this.height - } - ); - - // Hiding everything - // TODO: find a more sensible way to perform this operation - this.hideDOMElements(this.domElements.nodes); - this.hideDOMElements(this.domElements.edges); - this.hideDOMElements(this.domElements.labels); - - // Find which nodes are on screen - this.edgesOnScreen = []; - this.nodesOnScreen = this.camera.quadtree.area( - this.camera.getRectangle(this.width, this.height) - ); - - // Node index - for (a = this.nodesOnScreen, i = 0, l = a.length; i < l; i++) - index[a[i].id] = a[i]; - - // Find which edges are on screen - for (a = graph.edges(), i = 0, l = a.length; i < l; i++) { - o = a[i]; - if ( - (index[o.source] || index[o.target]) && - (!o.hidden && !nodes(o.source).hidden && !nodes(o.target).hidden) - ) - this.edgesOnScreen.push(o); - } - - // Display nodes - //--------------- - renderers = sigma.svg.nodes; - subrenderers = sigma.svg.labels; - - //-- First we create the nodes which are not already created - if (drawNodes) - for (a = this.nodesOnScreen, i = 0, l = a.length; i < l; i++) { - if (!a[i].hidden && !this.domElements.nodes[a[i].id]) { - - // Node - e = (renderers[a[i].type] || renderers.def).create( - a[i], - embedSettings - ); - - this.domElements.nodes[a[i].id] = e; - this.domElements.groups.nodes.appendChild(e); - - // Label - e = (subrenderers[a[i].type] || subrenderers.def).create( - a[i], - embedSettings - ); - - this.domElements.labels[a[i].id] = e; - this.domElements.groups.labels.appendChild(e); - } - } - - //-- Second we update the nodes - if (drawNodes) - for (a = this.nodesOnScreen, i = 0, l = a.length; i < l; i++) { - - if (a[i].hidden) - continue; - - // Node - (renderers[a[i].type] || renderers.def).update( - a[i], - this.domElements.nodes[a[i].id], - embedSettings - ); - - // Label - (subrenderers[a[i].type] || subrenderers.def).update( - a[i], - this.domElements.labels[a[i].id], - embedSettings - ); - } - - // Display edges - //--------------- - renderers = sigma.svg.edges; - - //-- First we create the edges which are not already created - if (drawEdges) - for (a = this.edgesOnScreen, i = 0, l = a.length; i < l; i++) { - if (!this.domElements.edges[a[i].id]) { - source = nodes(a[i].source); - target = nodes(a[i].target); - - e = (renderers[a[i].type] || renderers.def).create( - a[i], - source, - target, - embedSettings - ); - - this.domElements.edges[a[i].id] = e; - this.domElements.groups.edges.appendChild(e); - } - } - - //-- Second we update the edges - if (drawEdges) - for (a = this.edgesOnScreen, i = 0, l = a.length; i < l; i++) { - source = nodes(a[i].source); - target = nodes(a[i].target); - - (renderers[a[i].type] || renderers.def).update( - a[i], - this.domElements.edges[a[i].id], - source, - target, - embedSettings - ); - } - - this.dispatchEvent('render'); - - return this; - }; - - /** - * This method creates a DOM element of the specified type, switches its - * position to "absolute", references it to the domElements attribute, and - * finally appends it to the container. - * - * @param {string} tag The label tag. - * @param {string} id The id of the element (to store it in "domElements"). - */ - sigma.renderers.svg.prototype.initDOM = function(tag) { - var dom = document.createElementNS(this.settings('xmlns'), tag), - c = this.settings('classPrefix'), - g, - l, - i; - - dom.style.position = 'absolute'; - dom.setAttribute('class', c + '-svg'); - - // Setting SVG namespace - dom.setAttribute('xmlns', this.settings('xmlns')); - dom.setAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink'); - dom.setAttribute('version', '1.1'); - - // Creating the measurement canvas - var canvas = document.createElement('canvas'); - canvas.setAttribute('class', c + '-measurement-canvas'); - - // Appending elements - this.domElements.graph = this.container.appendChild(dom); - - // Creating groups - var groups = ['edges', 'nodes', 'labels', 'hovers']; - for (i = 0, l = groups.length; i < l; i++) { - g = document.createElementNS(this.settings('xmlns'), 'g'); - - g.setAttributeNS(null, 'id', c + '-group-' + groups[i]); - g.setAttributeNS(null, 'class', c + '-group'); - - this.domElements.groups[groups[i]] = - this.domElements.graph.appendChild(g); - } - - // Appending measurement canvas - this.container.appendChild(canvas); - this.measurementCanvas = canvas.getContext('2d'); - }; - - /** - * This method hides a batch of SVG DOM elements. - * - * @param {array} elements An array of elements to hide. - * @param {object} renderer The renderer to use. - * @return {sigma.renderers.svg} Returns the instance itself. - */ - sigma.renderers.svg.prototype.hideDOMElements = function(elements) { - var o, - i; - - for (i in elements) { - o = elements[i]; - sigma.svg.utils.hide(o); - } - - return this; - }; - - /** - * This method binds the hover events to the renderer. - * - * @param {string} prefix The renderer prefix. - */ - // TODO: add option about whether to display hovers or not - sigma.renderers.svg.prototype.bindHovers = function(prefix) { - var renderers = sigma.svg.hovers, - self = this, - hoveredNode; - - function overNode(e) { - var node = e.data.node, - embedSettings = self.settings.embedObjects({ - prefix: prefix - }); - - if (!embedSettings('enableHovering')) - return; - - var hover = (renderers[node.type] || renderers.def).create( - node, - self.domElements.nodes[node.id], - self.measurementCanvas, - embedSettings - ); - - self.domElements.hovers[node.id] = hover; - - // Inserting the hover in the dom - self.domElements.groups.hovers.appendChild(hover); - hoveredNode = node; - } - - function outNode(e) { - var node = e.data.node, - embedSettings = self.settings.embedObjects({ - prefix: prefix - }); - - if (!embedSettings('enableHovering')) - return; - - // Deleting element - self.domElements.groups.hovers.removeChild( - self.domElements.hovers[node.id] - ); - hoveredNode = null; - delete self.domElements.hovers[node.id]; - - // Reinstate - self.domElements.groups.nodes.appendChild( - self.domElements.nodes[node.id] - ); - } - - // OPTIMIZE: perform a real update rather than a deletion - function update() { - if (!hoveredNode) - return; - - var embedSettings = self.settings.embedObjects({ - prefix: prefix - }); - - // Deleting element before update - self.domElements.groups.hovers.removeChild( - self.domElements.hovers[hoveredNode.id] - ); - delete self.domElements.hovers[hoveredNode.id]; - - var hover = (renderers[hoveredNode.type] || renderers.def).create( - hoveredNode, - self.domElements.nodes[hoveredNode.id], - self.measurementCanvas, - embedSettings - ); - - self.domElements.hovers[hoveredNode.id] = hover; - - // Inserting the hover in the dom - self.domElements.groups.hovers.appendChild(hover); - } - - // Binding events - this.bind('overNode', overNode); - this.bind('outNode', outNode); - - // Update on render - this.bind('render', update); - }; - - /** - * This method resizes each DOM elements in the container and stores the new - * dimensions. Then, it renders the graph. - * - * @param {?number} width The new width of the container. - * @param {?number} height The new height of the container. - * @return {sigma.renderers.svg} Returns the instance itself. - */ - sigma.renderers.svg.prototype.resize = function(w, h) { - var oldWidth = this.width, - oldHeight = this.height, - pixelRatio = 1; - - if (w !== undefined && h !== undefined) { - this.width = w; - this.height = h; - } else { - this.width = this.container.offsetWidth; - this.height = this.container.offsetHeight; - - w = this.width; - h = this.height; - } - - if (oldWidth !== this.width || oldHeight !== this.height) { - this.domElements.graph.style.width = w + 'px'; - this.domElements.graph.style.height = h + 'px'; - - if (this.domElements.graph.tagName.toLowerCase() === 'svg') { - this.domElements.graph.setAttribute('width', (w * pixelRatio)); - this.domElements.graph.setAttribute('height', (h * pixelRatio)); - } - } - - return this; - }; - - - /** - * The labels, nodes and edges renderers are stored in the three following - * objects. When an element is drawn, its type will be checked and if a - * renderer with the same name exists, it will be used. If not found, the - * default renderer will be used instead. - * - * They are stored in different files, in the "./svg" folder. - */ - sigma.utils.pkg('sigma.svg.nodes'); - sigma.utils.pkg('sigma.svg.edges'); - sigma.utils.pkg('sigma.svg.labels'); -}).call(this); diff --git a/src/demo/static/sigmajs/renderers/sigma.renderers.webgl.js b/src/demo/static/sigmajs/renderers/sigma.renderers.webgl.js deleted file mode 100644 index b2a7baa48..000000000 --- a/src/demo/static/sigmajs/renderers/sigma.renderers.webgl.js +++ /dev/null @@ -1,693 +0,0 @@ -;(function(undefined) { - 'use strict'; - - if (typeof sigma === 'undefined') - throw 'sigma is not declared'; - - // Initialize packages: - sigma.utils.pkg('sigma.renderers'); - - /** - * This function is the constructor of the canvas sigma's renderer. - * - * @param {sigma.classes.graph} graph The graph to render. - * @param {sigma.classes.camera} camera The camera. - * @param {configurable} settings The sigma instance settings - * function. - * @param {object} object The options object. - * @return {sigma.renderers.canvas} The renderer instance. - */ - sigma.renderers.webgl = function(graph, camera, settings, options) { - if (typeof options !== 'object') - throw 'sigma.renderers.webgl: Wrong arguments.'; - - if (!(options.container instanceof HTMLElement)) - throw 'Container not found.'; - - var k, - i, - l, - a, - fn, - _self = this; - - sigma.classes.dispatcher.extend(this); - - // Conrad related attributes: - this.jobs = {}; - - Object.defineProperty(this, 'conradId', { - value: sigma.utils.id() - }); - - // Initialize main attributes: - this.graph = graph; - this.camera = camera; - this.contexts = {}; - this.domElements = {}; - this.options = options; - this.container = this.options.container; - this.settings = ( - typeof options.settings === 'object' && - options.settings - ) ? - settings.embedObjects(options.settings) : - settings; - - // Find the prefix: - this.options.prefix = this.camera.readPrefix; - - // Initialize programs hash - Object.defineProperty(this, 'nodePrograms', { - value: {} - }); - Object.defineProperty(this, 'edgePrograms', { - value: {} - }); - Object.defineProperty(this, 'nodeFloatArrays', { - value: {} - }); - Object.defineProperty(this, 'edgeFloatArrays', { - value: {} - }); - - // Initialize the DOM elements: - if (this.settings(options, 'batchEdgesDrawing')) { - this.initDOM('canvas', 'edges', true); - this.initDOM('canvas', 'nodes', true); - } else { - this.initDOM('canvas', 'scene', true); - this.contexts.nodes = this.contexts.scene; - this.contexts.edges = this.contexts.scene; - } - - this.initDOM('canvas', 'labels'); - this.initDOM('canvas', 'mouse'); - this.contexts.hover = this.contexts.mouse; - - // Initialize captors: - this.captors = []; - a = this.options.captors || [sigma.captors.mouse, sigma.captors.touch]; - for (i = 0, l = a.length; i < l; i++) { - fn = typeof a[i] === 'function' ? a[i] : sigma.captors[a[i]]; - this.captors.push( - new fn( - this.domElements.mouse, - this.camera, - this.settings - ) - ); - } - - // Deal with sigma events: - sigma.misc.bindEvents.call(this, this.camera.prefix); - sigma.misc.drawHovers.call(this, this.camera.prefix); - - this.resize(); - }; - - - - - /** - * This method will generate the nodes and edges float arrays. This step is - * separated from the "render" method, because to keep WebGL efficient, since - * all the camera and middlewares are modelised as matrices and they do not - * require the float arrays to be regenerated. - * - * Basically, when the user moves the camera or applies some specific linear - * transformations, this process step will be skipped, and the "render" - * method will efficiently refresh the rendering. - * - * And when the user modifies the graph colors or positions (applying a new - * layout or filtering the colors, for instance), this "process" step will be - * required to regenerate the float arrays. - * - * @return {sigma.renderers.webgl} Returns the instance itself. - */ - sigma.renderers.webgl.prototype.process = function() { - var a, - i, - l, - k, - type, - renderer, - graph = this.graph, - options = sigma.utils.extend(options, this.options); - - // Empty float arrays: - for (k in this.nodeFloatArrays) - delete this.nodeFloatArrays[k]; - - for (k in this.edgeFloatArrays) - delete this.edgeFloatArrays[k]; - - // Sort edges and nodes per types: - for (a = graph.edges(), i = 0, l = a.length; i < l; i++) { - type = a[i].type || this.settings(options, 'defaultEdgeType'); - k = (type && sigma.webgl.edges[type]) ? type : 'def'; - - if (!this.edgeFloatArrays[k]) - this.edgeFloatArrays[k] = { - edges: [] - }; - - this.edgeFloatArrays[k].edges.push(a[i]); - } - - for (a = graph.nodes(), i = 0, l = a.length; i < l; i++) { - type = a[i].type || this.settings(options, 'defaultNodeType'); - k = (type && sigma.webgl.nodes[type]) ? type : 'def'; - - if (!this.nodeFloatArrays[k]) - this.nodeFloatArrays[k] = { - nodes: [] - }; - - this.nodeFloatArrays[k].nodes.push(a[i]); - } - - // Push edges: - for (k in this.edgeFloatArrays) { - renderer = sigma.webgl.edges[k]; - - for (a = this.edgeFloatArrays[k].edges, i = 0, l = a.length; i < l; i++) { - if (!this.edgeFloatArrays[k].array) - this.edgeFloatArrays[k].array = new Float32Array( - a.length * renderer.POINTS * renderer.ATTRIBUTES - ); - - // Just check that the edge and both its extremities are visible: - if ( - !a[i].hidden && - !graph.nodes(a[i].source).hidden && - !graph.nodes(a[i].target).hidden - ) - renderer.addEdge( - a[i], - graph.nodes(a[i].source), - graph.nodes(a[i].target), - this.edgeFloatArrays[k].array, - i * renderer.POINTS * renderer.ATTRIBUTES, - options.prefix, - this.settings - ); - } - } - - // Push nodes: - for (k in this.nodeFloatArrays) { - renderer = sigma.webgl.nodes[k]; - - for (a = this.nodeFloatArrays[k].nodes, i = 0, l = a.length; i < l; i++) { - if (!this.nodeFloatArrays[k].array) - this.nodeFloatArrays[k].array = new Float32Array( - a.length * renderer.POINTS * renderer.ATTRIBUTES - ); - - // Just check that the edge and both its extremities are visible: - if ( - !a[i].hidden - ) - renderer.addNode( - a[i], - this.nodeFloatArrays[k].array, - i * renderer.POINTS * renderer.ATTRIBUTES, - options.prefix, - this.settings - ); - } - } - - return this; - }; - - - - - /** - * This method renders the graph. It basically calls each program (and - * generate them if they do not exist yet) to render nodes and edges, batched - * per renderer. - * - * As in the canvas renderer, it is possible to display edges, nodes and / or - * labels in batches, to make the whole thing way more scalable. - * - * @param {?object} params Eventually an object of options. - * @return {sigma.renderers.webgl} Returns the instance itself. - */ - sigma.renderers.webgl.prototype.render = function(params) { - var a, - i, - l, - k, - o, - program, - renderer, - self = this, - graph = this.graph, - nodesGl = this.contexts.nodes, - edgesGl = this.contexts.edges, - matrix = this.camera.getMatrix(), - options = sigma.utils.extend(params, this.options), - drawLabels = this.settings(options, 'drawLabels'), - drawEdges = this.settings(options, 'drawEdges'), - drawNodes = this.settings(options, 'drawNodes'); - - // Call the resize function: - this.resize(false); - - // Check the 'hideEdgesOnMove' setting: - if (this.settings(options, 'hideEdgesOnMove')) - if (this.camera.isAnimated || this.camera.isMoving) - drawEdges = false; - - // Clear canvases: - this.clear(); - - // Translate matrix to [width/2, height/2]: - matrix = sigma.utils.matrices.multiply( - matrix, - sigma.utils.matrices.translation(this.width / 2, this.height / 2) - ); - - // Kill running jobs: - for (k in this.jobs) - if (conrad.hasJob(k)) - conrad.killJob(k); - - if (drawEdges) { - if (this.settings(options, 'batchEdgesDrawing')) - (function() { - var a, - k, - i, - id, - job, - arr, - end, - start, - renderer, - batchSize, - currentProgram; - - id = 'edges_' + this.conradId; - batchSize = this.settings(options, 'webglEdgesBatchSize'); - a = Object.keys(this.edgeFloatArrays); - - if (!a.length) - return; - i = 0; - renderer = sigma.webgl.edges[a[i]]; - arr = this.edgeFloatArrays[a[i]].array; - start = 0; - end = Math.min( - start + batchSize * renderer.POINTS, - arr.length / renderer.ATTRIBUTES - ); - - job = function() { - // Check program: - if (!this.edgePrograms[a[i]]) - this.edgePrograms[a[i]] = renderer.initProgram(edgesGl); - - if (start < end) { - edgesGl.useProgram(this.edgePrograms[a[i]]); - renderer.render( - edgesGl, - this.edgePrograms[a[i]], - arr, - { - settings: this.settings, - matrix: matrix, - width: this.width, - height: this.height, - ratio: this.camera.ratio, - scalingRatio: this.settings( - options, - 'webglOversamplingRatio' - ), - start: start, - count: end - start - } - ); - } - - // Catch job's end: - if ( - end >= arr.length / renderer.ATTRIBUTES && - i === a.length - 1 - ) { - delete this.jobs[id]; - return false; - } - - if (end >= arr.length / renderer.ATTRIBUTES) { - i++; - arr = this.edgeFloatArrays[a[i]].array; - renderer = sigma.webgl.edges[a[i]]; - start = 0; - end = Math.min( - start + batchSize * renderer.POINTS, - arr.length / renderer.ATTRIBUTES - ); - } else { - start = end; - end = Math.min( - start + batchSize * renderer.POINTS, - arr.length / renderer.ATTRIBUTES - ); - } - - return true; - }; - - this.jobs[id] = job; - conrad.addJob(id, job.bind(this)); - }).call(this); - else { - for (k in this.edgeFloatArrays) { - renderer = sigma.webgl.edges[k]; - - // Check program: - if (!this.edgePrograms[k]) - this.edgePrograms[k] = renderer.initProgram(edgesGl); - - // Render - if (this.edgeFloatArrays[k]) { - edgesGl.useProgram(this.edgePrograms[k]); - renderer.render( - edgesGl, - this.edgePrograms[k], - this.edgeFloatArrays[k].array, - { - settings: this.settings, - matrix: matrix, - width: this.width, - height: this.height, - ratio: this.camera.ratio, - scalingRatio: this.settings(options, 'webglOversamplingRatio') - } - ); - } - } - } - } - - if (drawNodes) { - // Enable blending: - nodesGl.blendFunc(nodesGl.SRC_ALPHA, nodesGl.ONE_MINUS_SRC_ALPHA); - nodesGl.enable(nodesGl.BLEND); - - for (k in this.nodeFloatArrays) { - renderer = sigma.webgl.nodes[k]; - - // Check program: - if (!this.nodePrograms[k]) - this.nodePrograms[k] = renderer.initProgram(nodesGl); - - // Render - if (this.nodeFloatArrays[k]) { - nodesGl.useProgram(this.nodePrograms[k]); - renderer.render( - nodesGl, - this.nodePrograms[k], - this.nodeFloatArrays[k].array, - { - settings: this.settings, - matrix: matrix, - width: this.width, - height: this.height, - ratio: this.camera.ratio, - scalingRatio: this.settings(options, 'webglOversamplingRatio') - } - ); - } - } - } - - if (drawLabels) { - a = this.camera.quadtree.area( - this.camera.getRectangle(this.width, this.height) - ); - - // Apply camera view to these nodes: - this.camera.applyView( - undefined, - undefined, - { - nodes: a, - edges: [], - width: this.width, - height: this.height - } - ); - - o = function(key) { - return self.settings({ - prefix: self.camera.prefix - }, key); - }; - - for (i = 0, l = a.length; i < l; i++) - if (!a[i].hidden) - ( - sigma.canvas.labels[ - a[i].type || - this.settings(options, 'defaultNodeType') - ] || sigma.canvas.labels.def - )(a[i], this.contexts.labels, o); - } - - this.dispatchEvent('render'); - - return this; - }; - - - - - /** - * This method creates a DOM element of the specified type, switches its - * position to "absolute", references it to the domElements attribute, and - * finally appends it to the container. - * - * @param {string} tag The label tag. - * @param {string} id The id of the element (to store it in - * "domElements"). - * @param {?boolean} webgl Will init the WebGL context if true. - */ - sigma.renderers.webgl.prototype.initDOM = function(tag, id, webgl) { - var gl, - dom = document.createElement(tag), - self = this; - - dom.style.position = 'absolute'; - dom.setAttribute('class', 'sigma-' + id); - - this.domElements[id] = dom; - this.container.appendChild(dom); - - if (tag.toLowerCase() === 'canvas') { - this.contexts[id] = dom.getContext(webgl ? 'experimental-webgl' : '2d', { - preserveDrawingBuffer: true - }); - - // Adding webgl context loss listeners - if (webgl) { - dom.addEventListener('webglcontextlost', function(e) { - e.preventDefault(); - }, false); - - dom.addEventListener('webglcontextrestored', function(e) { - self.render(); - }, false); - } - } - }; - - /** - * This method resizes each DOM elements in the container and stores the new - * dimensions. Then, it renders the graph. - * - * @param {?number} width The new width of the container. - * @param {?number} height The new height of the container. - * @return {sigma.renderers.webgl} Returns the instance itself. - */ - sigma.renderers.webgl.prototype.resize = function(w, h) { - var k, - oldWidth = this.width, - oldHeight = this.height; - - if (w !== undefined && h !== undefined) { - this.width = w; - this.height = h; - } else { - this.width = this.container.offsetWidth; - this.height = this.container.offsetHeight; - - w = this.width; - h = this.height; - } - - if (oldWidth !== this.width || oldHeight !== this.height) { - for (k in this.domElements) { - this.domElements[k].style.width = w + 'px'; - this.domElements[k].style.height = h + 'px'; - - if (this.domElements[k].tagName.toLowerCase() === 'canvas') { - // If simple 2D canvas: - if (this.contexts[k] && this.contexts[k].scale) { - this.domElements[k].setAttribute('width', w + 'px'); - this.domElements[k].setAttribute('height', h + 'px'); - } else { - this.domElements[k].setAttribute( - 'width', - (w * this.settings('webglOversamplingRatio')) + 'px' - ); - this.domElements[k].setAttribute( - 'height', - (h * this.settings('webglOversamplingRatio')) + 'px' - ); - } - } - } - } - - // Scale: - for (k in this.contexts) - if (this.contexts[k] && this.contexts[k].viewport) - this.contexts[k].viewport( - 0, - 0, - this.width * this.settings('webglOversamplingRatio'), - this.height * this.settings('webglOversamplingRatio') - ); - - return this; - }; - - /** - * This method clears each canvas. - * - * @return {sigma.renderers.webgl} Returns the instance itself. - */ - sigma.renderers.webgl.prototype.clear = function() { - var k; - - for (k in this.domElements) - if (this.domElements[k].tagName === 'CANVAS') - this.domElements[k].width = this.domElements[k].width; - - this.contexts.nodes.clear(this.contexts.nodes.COLOR_BUFFER_BIT); - this.contexts.edges.clear(this.contexts.edges.COLOR_BUFFER_BIT); - - return this; - }; - - /** - * This method kills contexts and other attributes. - */ - sigma.renderers.webgl.prototype.kill = function() { - var k, - captor; - - // Kill captors: - while ((captor = this.captors.pop())) - captor.kill(); - delete this.captors; - - // Kill contexts: - for (k in this.domElements) { - this.domElements[k].parentNode.removeChild(this.domElements[k]); - delete this.domElements[k]; - delete this.contexts[k]; - } - delete this.domElements; - delete this.contexts; - }; - - - - - /** - * The object "sigma.webgl.nodes" contains the different WebGL node - * renderers. The default one draw nodes as discs. Here are the attributes - * any node renderer must have: - * - * {number} POINTS The number of points required to draw a node. - * {number} ATTRIBUTES The number of attributes needed to draw one point. - * {function} addNode A function that adds a node to the data stack that - * will be given to the buffer. Here is the arguments: - * > {object} node - * > {number} index The node index in the - * nodes array. - * > {Float32Array} data The stack. - * > {object} options Some options. - * {function} render The function that will effectively render the nodes - * into the buffer. - * > {WebGLRenderingContext} gl - * > {WebGLProgram} program - * > {Float32Array} data The stack to give to the - * buffer. - * > {object} params An object containing some - * options, like width, - * height, the camera ratio. - * {function} initProgram The function that will initiate the program, with - * the relevant shaders and parameters. It must return - * the newly created program. - * - * Check sigma.webgl.nodes.def or sigma.webgl.nodes.fast to see how it - * works more precisely. - */ - sigma.utils.pkg('sigma.webgl.nodes'); - - - - - /** - * The object "sigma.webgl.edges" contains the different WebGL edge - * renderers. The default one draw edges as direct lines. Here are the - * attributes any edge renderer must have: - * - * {number} POINTS The number of points required to draw an edge. - * {number} ATTRIBUTES The number of attributes needed to draw one point. - * {function} addEdge A function that adds an edge to the data stack that - * will be given to the buffer. Here is the arguments: - * > {object} edge - * > {object} source - * > {object} target - * > {Float32Array} data The stack. - * > {object} options Some options. - * {function} render The function that will effectively render the edges - * into the buffer. - * > {WebGLRenderingContext} gl - * > {WebGLProgram} program - * > {Float32Array} data The stack to give to the - * buffer. - * > {object} params An object containing some - * options, like width, - * height, the camera ratio. - * {function} initProgram The function that will initiate the program, with - * the relevant shaders and parameters. It must return - * the newly created program. - * - * Check sigma.webgl.edges.def or sigma.webgl.edges.fast to see how it - * works more precisely. - */ - sigma.utils.pkg('sigma.webgl.edges'); - - - - - /** - * The object "sigma.canvas.labels" contains the different - * label renderers for the WebGL renderer. Since displaying texts in WebGL is - * definitely painful and since there a way less labels to display than nodes - * or edges, the default renderer simply renders them in a canvas. - * - * A labels renderer is a simple function, taking as arguments the related - * node, the renderer and a settings function. - */ - sigma.utils.pkg('sigma.canvas.labels'); -}).call(this); diff --git a/src/demo/static/sigmajs/renderers/svg/sigma.svg.edges.curve.js b/src/demo/static/sigmajs/renderers/svg/sigma.svg.edges.curve.js deleted file mode 100644 index 37f82e691..000000000 --- a/src/demo/static/sigmajs/renderers/svg/sigma.svg.edges.curve.js +++ /dev/null @@ -1,84 +0,0 @@ -;(function() { - 'use strict'; - - sigma.utils.pkg('sigma.svg.edges'); - - /** - * The curve edge renderer. It renders the node as a bezier curve. - */ - sigma.svg.edges.curve = { - - /** - * SVG Element creation. - * - * @param {object} edge The edge object. - * @param {object} source The source node object. - * @param {object} target The target node object. - * @param {configurable} settings The settings function. - */ - create: function(edge, source, target, settings) { - var color = edge.color, - prefix = settings('prefix') || '', - edgeColor = settings('edgeColor'), - defaultNodeColor = settings('defaultNodeColor'), - defaultEdgeColor = settings('defaultEdgeColor'); - - if (!color) - switch (edgeColor) { - case 'source': - color = source.color || defaultNodeColor; - break; - case 'target': - color = target.color || defaultNodeColor; - break; - default: - color = defaultEdgeColor; - break; - } - - var path = document.createElementNS(settings('xmlns'), 'path'); - - // Attributes - path.setAttributeNS(null, 'data-edge-id', edge.id); - path.setAttributeNS(null, 'class', settings('classPrefix') + '-edge'); - path.setAttributeNS(null, 'stroke', color); - - return path; - }, - - /** - * SVG Element update. - * - * @param {object} edge The edge object. - * @param {DOMElement} line The line DOM Element. - * @param {object} source The source node object. - * @param {object} target The target node object. - * @param {configurable} settings The settings function. - */ - update: function(edge, path, source, target, settings) { - var prefix = settings('prefix') || ''; - - path.setAttributeNS(null, 'stroke-width', edge[prefix + 'size'] || 1); - - // Control point - var cx = (source[prefix + 'x'] + target[prefix + 'x']) / 2 + - (target[prefix + 'y'] - source[prefix + 'y']) / 4, - cy = (source[prefix + 'y'] + target[prefix + 'y']) / 2 + - (source[prefix + 'x'] - target[prefix + 'x']) / 4; - - // Path - var p = 'M' + source[prefix + 'x'] + ',' + source[prefix + 'y'] + ' ' + - 'Q' + cx + ',' + cy + ' ' + - target[prefix + 'x'] + ',' + target[prefix + 'y']; - - // Updating attributes - path.setAttributeNS(null, 'd', p); - path.setAttributeNS(null, 'fill', 'none'); - - // Showing - path.style.display = ''; - - return this; - } - }; -})(); diff --git a/src/demo/static/sigmajs/renderers/svg/sigma.svg.edges.def.js b/src/demo/static/sigmajs/renderers/svg/sigma.svg.edges.def.js deleted file mode 100644 index e48d57b1f..000000000 --- a/src/demo/static/sigmajs/renderers/svg/sigma.svg.edges.def.js +++ /dev/null @@ -1,73 +0,0 @@ -;(function() { - 'use strict'; - - sigma.utils.pkg('sigma.svg.edges'); - - /** - * The default edge renderer. It renders the node as a simple line. - */ - sigma.svg.edges.def = { - - /** - * SVG Element creation. - * - * @param {object} edge The edge object. - * @param {object} source The source node object. - * @param {object} target The target node object. - * @param {configurable} settings The settings function. - */ - create: function(edge, source, target, settings) { - var color = edge.color, - prefix = settings('prefix') || '', - edgeColor = settings('edgeColor'), - defaultNodeColor = settings('defaultNodeColor'), - defaultEdgeColor = settings('defaultEdgeColor'); - - if (!color) - switch (edgeColor) { - case 'source': - color = source.color || defaultNodeColor; - break; - case 'target': - color = target.color || defaultNodeColor; - break; - default: - color = defaultEdgeColor; - break; - } - - var line = document.createElementNS(settings('xmlns'), 'line'); - - // Attributes - line.setAttributeNS(null, 'data-edge-id', edge.id); - line.setAttributeNS(null, 'class', settings('classPrefix') + '-edge'); - line.setAttributeNS(null, 'stroke', color); - - return line; - }, - - /** - * SVG Element update. - * - * @param {object} edge The edge object. - * @param {DOMElement} line The line DOM Element. - * @param {object} source The source node object. - * @param {object} target The target node object. - * @param {configurable} settings The settings function. - */ - update: function(edge, line, source, target, settings) { - var prefix = settings('prefix') || ''; - - line.setAttributeNS(null, 'stroke-width', edge[prefix + 'size'] || 1); - line.setAttributeNS(null, 'x1', source[prefix + 'x']); - line.setAttributeNS(null, 'y1', source[prefix + 'y']); - line.setAttributeNS(null, 'x2', target[prefix + 'x']); - line.setAttributeNS(null, 'y2', target[prefix + 'y']); - - // Showing - line.style.display = ''; - - return this; - } - }; -})(); diff --git a/src/demo/static/sigmajs/renderers/svg/sigma.svg.hovers.def.js b/src/demo/static/sigmajs/renderers/svg/sigma.svg.hovers.def.js deleted file mode 100644 index 6525ab9ad..000000000 --- a/src/demo/static/sigmajs/renderers/svg/sigma.svg.hovers.def.js +++ /dev/null @@ -1,113 +0,0 @@ -;(function(undefined) { - 'use strict'; - - if (typeof sigma === 'undefined') - throw 'sigma is not declared'; - - // Initialize packages: - sigma.utils.pkg('sigma.svg.hovers'); - - /** - * The default hover renderer. - */ - sigma.svg.hovers.def = { - - /** - * SVG Element creation. - * - * @param {object} node The node object. - * @param {CanvasElement} measurementCanvas A fake canvas handled by - * the svg to perform some measurements and - * passed by the renderer. - * @param {DOMElement} nodeCircle The node DOM Element. - * @param {configurable} settings The settings function. - */ - create: function(node, nodeCircle, measurementCanvas, settings) { - - // Defining visual properties - var x, - y, - w, - h, - e, - d, - fontStyle = settings('hoverFontStyle') || settings('fontStyle'), - prefix = settings('prefix') || '', - size = node[prefix + 'size'], - fontSize = (settings('labelSize') === 'fixed') ? - settings('defaultLabelSize') : - settings('labelSizeRatio') * size, - fontColor = (settings('labelHoverColor') === 'node') ? - (node.color || settings('defaultNodeColor')) : - settings('defaultLabelHoverColor'); - - // Creating elements - var group = document.createElementNS(settings('xmlns'), 'g'), - rectangle = document.createElementNS(settings('xmlns'), 'rect'), - circle = document.createElementNS(settings('xmlns'), 'circle'), - text = document.createElementNS(settings('xmlns'), 'text'); - - // Defining properties - group.setAttributeNS(null, 'class', settings('classPrefix') + '-hover'); - group.setAttributeNS(null, 'data-node-id', node.id); - - if (typeof node.label === 'string') { - - // Text - text.innerHTML = node.label; - text.textContent = node.label; - text.setAttributeNS( - null, - 'class', - settings('classPrefix') + '-hover-label'); - text.setAttributeNS(null, 'font-size', fontSize); - text.setAttributeNS(null, 'font-family', settings('font')); - text.setAttributeNS(null, 'fill', fontColor); - text.setAttributeNS(null, 'x', - Math.round(node[prefix + 'x'] + size + 3)); - text.setAttributeNS(null, 'y', - Math.round(node[prefix + 'y'] + fontSize / 3)); - - // Measures - // OPTIMIZE: Find a better way than a measurement canvas - x = Math.round(node[prefix + 'x'] - fontSize / 2 - 2); - y = Math.round(node[prefix + 'y'] - fontSize / 2 - 2); - w = Math.round( - measurementCanvas.measureText(node.label).width + - fontSize / 2 + size + 9 - ); - h = Math.round(fontSize + 4); - e = Math.round(fontSize / 2 + 2); - - // Circle - circle.setAttributeNS( - null, - 'class', - settings('classPrefix') + '-hover-area'); - circle.setAttributeNS(null, 'fill', '#fff'); - circle.setAttributeNS(null, 'cx', node[prefix + 'x']); - circle.setAttributeNS(null, 'cy', node[prefix + 'y']); - circle.setAttributeNS(null, 'r', e); - - // Rectangle - rectangle.setAttributeNS( - null, - 'class', - settings('classPrefix') + '-hover-area'); - rectangle.setAttributeNS(null, 'fill', '#fff'); - rectangle.setAttributeNS(null, 'x', node[prefix + 'x'] + e / 4); - rectangle.setAttributeNS(null, 'y', node[prefix + 'y'] - e); - rectangle.setAttributeNS(null, 'width', w); - rectangle.setAttributeNS(null, 'height', h); - } - - // Appending childs - group.appendChild(circle); - group.appendChild(rectangle); - group.appendChild(text); - group.appendChild(nodeCircle); - - return group; - } - }; -}).call(this); diff --git a/src/demo/static/sigmajs/renderers/svg/sigma.svg.labels.def.js b/src/demo/static/sigmajs/renderers/svg/sigma.svg.labels.def.js deleted file mode 100644 index 4027c83b6..000000000 --- a/src/demo/static/sigmajs/renderers/svg/sigma.svg.labels.def.js +++ /dev/null @@ -1,80 +0,0 @@ -;(function(undefined) { - 'use strict'; - - if (typeof sigma === 'undefined') - throw 'sigma is not declared'; - - // Initialize packages: - sigma.utils.pkg('sigma.svg.labels'); - - /** - * The default label renderer. It renders the label as a simple text. - */ - sigma.svg.labels.def = { - - /** - * SVG Element creation. - * - * @param {object} node The node object. - * @param {configurable} settings The settings function. - */ - create: function(node, settings) { - var prefix = settings('prefix') || '', - size = node[prefix + 'size'], - text = document.createElementNS(settings('xmlns'), 'text'); - - var fontSize = (settings('labelSize') === 'fixed') ? - settings('defaultLabelSize') : - settings('labelSizeRatio') * size; - - var fontColor = (settings('labelColor') === 'node') ? - (node.color || settings('defaultNodeColor')) : - settings('defaultLabelColor'); - - text.setAttributeNS(null, 'data-label-target', node.id); - text.setAttributeNS(null, 'class', settings('classPrefix') + '-label'); - text.setAttributeNS(null, 'font-size', fontSize); - text.setAttributeNS(null, 'font-family', settings('font')); - text.setAttributeNS(null, 'fill', fontColor); - - text.innerHTML = node.label; - text.textContent = node.label; - - return text; - }, - - /** - * SVG Element update. - * - * @param {object} node The node object. - * @param {DOMElement} text The label DOM element. - * @param {configurable} settings The settings function. - */ - update: function(node, text, settings) { - var prefix = settings('prefix') || '', - size = node[prefix + 'size']; - - var fontSize = (settings('labelSize') === 'fixed') ? - settings('defaultLabelSize') : - settings('labelSizeRatio') * size; - - // Case when we don't want to display the label - if (!settings('forceLabels') && size < settings('labelThreshold')) - return; - - if (typeof node.label !== 'string') - return; - - // Updating - text.setAttributeNS(null, 'x', - Math.round(node[prefix + 'x'] + size + 3)); - text.setAttributeNS(null, 'y', - Math.round(node[prefix + 'y'] + fontSize / 3)); - - // Showing - text.style.display = ''; - - return this; - } - }; -}).call(this); diff --git a/src/demo/static/sigmajs/renderers/svg/sigma.svg.nodes.def.js b/src/demo/static/sigmajs/renderers/svg/sigma.svg.nodes.def.js deleted file mode 100644 index 4c01b7a44..000000000 --- a/src/demo/static/sigmajs/renderers/svg/sigma.svg.nodes.def.js +++ /dev/null @@ -1,58 +0,0 @@ -;(function() { - 'use strict'; - - sigma.utils.pkg('sigma.svg.nodes'); - - /** - * The default node renderer. It renders the node as a simple disc. - */ - sigma.svg.nodes.def = { - - /** - * SVG Element creation. - * - * @param {object} node The node object. - * @param {configurable} settings The settings function. - */ - create: function(node, settings) { - var prefix = settings('prefix') || '', - circle = document.createElementNS(settings('xmlns'), 'circle'); - - // Defining the node's circle - circle.setAttributeNS(null, 'data-node-id', node.id); - circle.setAttributeNS(null, 'class', settings('classPrefix') + '-node'); - circle.setAttributeNS( - null, 'fill', node.color || settings('defaultNodeColor')); - - // Returning the DOM Element - return circle; - }, - - /** - * SVG Element update. - * - * @param {object} node The node object. - * @param {DOMElement} circle The node DOM element. - * @param {configurable} settings The settings function. - */ - update: function(node, circle, settings) { - var prefix = settings('prefix') || ''; - - // Applying changes - // TODO: optimize - check if necessary - circle.setAttributeNS(null, 'cx', node[prefix + 'x']); - circle.setAttributeNS(null, 'cy', node[prefix + 'y']); - circle.setAttributeNS(null, 'r', node[prefix + 'size']); - - // Updating only if not freestyle - if (!settings('freeStyle')) - circle.setAttributeNS( - null, 'fill', node.color || settings('defaultNodeColor')); - - // Showing - circle.style.display = ''; - - return this; - } - }; -})(); diff --git a/src/demo/static/sigmajs/renderers/svg/sigma.svg.utils.js b/src/demo/static/sigmajs/renderers/svg/sigma.svg.utils.js deleted file mode 100644 index f00e2e5ec..000000000 --- a/src/demo/static/sigmajs/renderers/svg/sigma.svg.utils.js +++ /dev/null @@ -1,31 +0,0 @@ -;(function() { - 'use strict'; - - sigma.utils.pkg('sigma.svg.utils'); - - /** - * Some useful functions used by sigma's SVG renderer. - */ - sigma.svg.utils = { - - /** - * SVG Element show. - * - * @param {DOMElement} element The DOM element to show. - */ - show: function(element) { - element.style.display = ''; - return this; - }, - - /** - * SVG Element hide. - * - * @param {DOMElement} element The DOM element to hide. - */ - hide: function(element) { - element.style.display = 'none'; - return this; - } - }; -})(); diff --git a/src/demo/static/sigmajs/renderers/webgl/sigma.webgl.edges.arrow.js b/src/demo/static/sigmajs/renderers/webgl/sigma.webgl.edges.arrow.js deleted file mode 100644 index 4b548acd2..000000000 --- a/src/demo/static/sigmajs/renderers/webgl/sigma.webgl.edges.arrow.js +++ /dev/null @@ -1,391 +0,0 @@ -;(function() { - 'use strict'; - - sigma.utils.pkg('sigma.webgl.edges'); - - /** - * This edge renderer will display edges as arrows going from the source node - * to the target node. To deal with edge thicknesses, the lines are made of - * three triangles: two forming rectangles, with the gl.TRIANGLES drawing - * mode. - * - * It is expensive, since drawing a single edge requires 9 points, each - * having a lot of attributes. - */ - sigma.webgl.edges.arrow = { - POINTS: 9, - ATTRIBUTES: 11, - addEdge: function(edge, source, target, data, i, prefix, settings) { - var w = (edge[prefix + 'size'] || 1) / 2, - x1 = source[prefix + 'x'], - y1 = source[prefix + 'y'], - x2 = target[prefix + 'x'], - y2 = target[prefix + 'y'], - targetSize = target[prefix + 'size'], - color = edge.color; - - if (!color) - switch (settings('edgeColor')) { - case 'source': - color = source.color || settings('defaultNodeColor'); - break; - case 'target': - color = target.color || settings('defaultNodeColor'); - break; - default: - color = settings('defaultEdgeColor'); - break; - } - - // Normalize color: - color = sigma.utils.floatColor(color); - - data[i++] = x1; - data[i++] = y1; - data[i++] = x2; - data[i++] = y2; - data[i++] = w; - data[i++] = targetSize; - data[i++] = 0.0; - data[i++] = 0.0; - data[i++] = 0.0; - data[i++] = 0.0; - data[i++] = color; - - data[i++] = x2; - data[i++] = y2; - data[i++] = x1; - data[i++] = y1; - data[i++] = w; - data[i++] = targetSize; - data[i++] = 1.0; - data[i++] = 1.0; - data[i++] = 0.0; - data[i++] = 0.0; - data[i++] = color; - - data[i++] = x2; - data[i++] = y2; - data[i++] = x1; - data[i++] = y1; - data[i++] = w; - data[i++] = targetSize; - data[i++] = 1.0; - data[i++] = 0.0; - data[i++] = 0.0; - data[i++] = 0.0; - data[i++] = color; - - data[i++] = x2; - data[i++] = y2; - data[i++] = x1; - data[i++] = y1; - data[i++] = w; - data[i++] = targetSize; - data[i++] = 1.0; - data[i++] = 0.0; - data[i++] = 0.0; - data[i++] = 0.0; - data[i++] = color; - - data[i++] = x1; - data[i++] = y1; - data[i++] = x2; - data[i++] = y2; - data[i++] = w; - data[i++] = targetSize; - data[i++] = 0.0; - data[i++] = 1.0; - data[i++] = 0.0; - data[i++] = 0.0; - data[i++] = color; - - data[i++] = x1; - data[i++] = y1; - data[i++] = x2; - data[i++] = y2; - data[i++] = w; - data[i++] = targetSize; - data[i++] = 0.0; - data[i++] = 0.0; - data[i++] = 0.0; - data[i++] = 0.0; - data[i++] = color; - - // Arrow head: - data[i++] = x2; - data[i++] = y2; - data[i++] = x1; - data[i++] = y1; - data[i++] = w; - data[i++] = targetSize; - data[i++] = 1.0; - data[i++] = 0.0; - data[i++] = 1.0; - data[i++] = -1.0; - data[i++] = color; - - data[i++] = x2; - data[i++] = y2; - data[i++] = x1; - data[i++] = y1; - data[i++] = w; - data[i++] = targetSize; - data[i++] = 1.0; - data[i++] = 0.0; - data[i++] = 1.0; - data[i++] = 0.0; - data[i++] = color; - - data[i++] = x2; - data[i++] = y2; - data[i++] = x1; - data[i++] = y1; - data[i++] = w; - data[i++] = targetSize; - data[i++] = 1.0; - data[i++] = 0.0; - data[i++] = 1.0; - data[i++] = 1.0; - data[i++] = color; - }, - render: function(gl, program, data, params) { - var buffer; - - // Define attributes: - var positionLocation1 = - gl.getAttribLocation(program, 'a_pos1'), - positionLocation2 = - gl.getAttribLocation(program, 'a_pos2'), - thicknessLocation = - gl.getAttribLocation(program, 'a_thickness'), - targetSizeLocation = - gl.getAttribLocation(program, 'a_tSize'), - delayLocation = - gl.getAttribLocation(program, 'a_delay'), - minusLocation = - gl.getAttribLocation(program, 'a_minus'), - headLocation = - gl.getAttribLocation(program, 'a_head'), - headPositionLocation = - gl.getAttribLocation(program, 'a_headPosition'), - colorLocation = - gl.getAttribLocation(program, 'a_color'), - resolutionLocation = - gl.getUniformLocation(program, 'u_resolution'), - matrixLocation = - gl.getUniformLocation(program, 'u_matrix'), - matrixHalfPiLocation = - gl.getUniformLocation(program, 'u_matrixHalfPi'), - matrixHalfPiMinusLocation = - gl.getUniformLocation(program, 'u_matrixHalfPiMinus'), - ratioLocation = - gl.getUniformLocation(program, 'u_ratio'), - nodeRatioLocation = - gl.getUniformLocation(program, 'u_nodeRatio'), - arrowHeadLocation = - gl.getUniformLocation(program, 'u_arrowHead'), - scaleLocation = - gl.getUniformLocation(program, 'u_scale'); - - buffer = gl.createBuffer(); - gl.bindBuffer(gl.ARRAY_BUFFER, buffer); - gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW); - - gl.uniform2f(resolutionLocation, params.width, params.height); - gl.uniform1f( - ratioLocation, - params.ratio / Math.pow(params.ratio, params.settings('edgesPowRatio')) - ); - gl.uniform1f( - nodeRatioLocation, - Math.pow(params.ratio, params.settings('nodesPowRatio')) / - params.ratio - ); - gl.uniform1f(arrowHeadLocation, 5.0); - gl.uniform1f(scaleLocation, params.scalingRatio); - gl.uniformMatrix3fv(matrixLocation, false, params.matrix); - gl.uniformMatrix2fv( - matrixHalfPiLocation, - false, - sigma.utils.matrices.rotation(Math.PI / 2, true) - ); - gl.uniformMatrix2fv( - matrixHalfPiMinusLocation, - false, - sigma.utils.matrices.rotation(-Math.PI / 2, true) - ); - - gl.enableVertexAttribArray(positionLocation1); - gl.enableVertexAttribArray(positionLocation2); - gl.enableVertexAttribArray(thicknessLocation); - gl.enableVertexAttribArray(targetSizeLocation); - gl.enableVertexAttribArray(delayLocation); - gl.enableVertexAttribArray(minusLocation); - gl.enableVertexAttribArray(headLocation); - gl.enableVertexAttribArray(headPositionLocation); - gl.enableVertexAttribArray(colorLocation); - - gl.vertexAttribPointer(positionLocation1, - 2, - gl.FLOAT, - false, - this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT, - 0 - ); - gl.vertexAttribPointer(positionLocation2, - 2, - gl.FLOAT, - false, - this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT, - 8 - ); - gl.vertexAttribPointer(thicknessLocation, - 1, - gl.FLOAT, - false, - this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT, - 16 - ); - gl.vertexAttribPointer(targetSizeLocation, - 1, - gl.FLOAT, - false, - this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT, - 20 - ); - gl.vertexAttribPointer(delayLocation, - 1, - gl.FLOAT, - false, - this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT, - 24 - ); - gl.vertexAttribPointer(minusLocation, - 1, - gl.FLOAT, - false, - this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT, - 28 - ); - gl.vertexAttribPointer(headLocation, - 1, - gl.FLOAT, - false, - this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT, - 32 - ); - gl.vertexAttribPointer(headPositionLocation, - 1, - gl.FLOAT, - false, - this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT, - 36 - ); - gl.vertexAttribPointer(colorLocation, - 1, - gl.FLOAT, - false, - this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT, - 40 - ); - - gl.drawArrays( - gl.TRIANGLES, - params.start || 0, - params.count || (data.length / this.ATTRIBUTES) - ); - }, - initProgram: function(gl) { - var vertexShader, - fragmentShader, - program; - - vertexShader = sigma.utils.loadShader( - gl, - [ - 'attribute vec2 a_pos1;', - 'attribute vec2 a_pos2;', - 'attribute float a_thickness;', - 'attribute float a_tSize;', - 'attribute float a_delay;', - 'attribute float a_minus;', - 'attribute float a_head;', - 'attribute float a_headPosition;', - 'attribute float a_color;', - - 'uniform vec2 u_resolution;', - 'uniform float u_ratio;', - 'uniform float u_nodeRatio;', - 'uniform float u_arrowHead;', - 'uniform float u_scale;', - 'uniform mat3 u_matrix;', - 'uniform mat2 u_matrixHalfPi;', - 'uniform mat2 u_matrixHalfPiMinus;', - - 'varying vec4 color;', - - 'void main() {', - // Find the good point: - 'vec2 pos = normalize(a_pos2 - a_pos1);', - - 'mat2 matrix = (1.0 - a_head) *', - '(', - 'a_minus * u_matrixHalfPiMinus +', - '(1.0 - a_minus) * u_matrixHalfPi', - ') + a_head * (', - 'a_headPosition * u_matrixHalfPiMinus * 0.6 +', - '(a_headPosition * a_headPosition - 1.0) * mat2(1.0)', - ');', - - 'pos = a_pos1 + (', - // Deal with body: - '(1.0 - a_head) * a_thickness * u_ratio * matrix * pos +', - // Deal with head: - 'a_head * u_arrowHead * a_thickness * u_ratio * matrix * pos +', - // Deal with delay: - 'a_delay * pos * (', - 'a_tSize / u_nodeRatio +', - 'u_arrowHead * a_thickness * u_ratio', - ')', - ');', - - // Scale from [[-1 1] [-1 1]] to the container: - 'gl_Position = vec4(', - '((u_matrix * vec3(pos, 1)).xy /', - 'u_resolution * 2.0 - 1.0) * vec2(1, -1),', - '0,', - '1', - ');', - - // Extract the color: - 'float c = a_color;', - 'color.b = mod(c, 256.0); c = floor(c / 256.0);', - 'color.g = mod(c, 256.0); c = floor(c / 256.0);', - 'color.r = mod(c, 256.0); c = floor(c / 256.0); color /= 255.0;', - 'color.a = 1.0;', - '}' - ].join('\n'), - gl.VERTEX_SHADER - ); - - fragmentShader = sigma.utils.loadShader( - gl, - [ - 'precision mediump float;', - - 'varying vec4 color;', - - 'void main(void) {', - 'gl_FragColor = color;', - '}' - ].join('\n'), - gl.FRAGMENT_SHADER - ); - - program = sigma.utils.loadProgram(gl, [vertexShader, fragmentShader]); - - return program; - } - }; -})(); diff --git a/src/demo/static/sigmajs/renderers/webgl/sigma.webgl.edges.def.js b/src/demo/static/sigmajs/renderers/webgl/sigma.webgl.edges.def.js deleted file mode 100644 index 6931bb586..000000000 --- a/src/demo/static/sigmajs/renderers/webgl/sigma.webgl.edges.def.js +++ /dev/null @@ -1,258 +0,0 @@ -;(function() { - 'use strict'; - - sigma.utils.pkg('sigma.webgl.edges'); - - /** - * This edge renderer will display edges as lines going from the source node - * to the target node. To deal with edge thicknesses, the lines are made of - * two triangles forming rectangles, with the gl.TRIANGLES drawing mode. - * - * It is expensive, since drawing a single edge requires 6 points, each - * having 7 attributes (source position, target position, thickness, color - * and a flag indicating which vertice of the rectangle it is). - */ - sigma.webgl.edges.def = { - POINTS: 6, - ATTRIBUTES: 7, - addEdge: function(edge, source, target, data, i, prefix, settings) { - var w = (edge[prefix + 'size'] || 1) / 2, - x1 = source[prefix + 'x'], - y1 = source[prefix + 'y'], - x2 = target[prefix + 'x'], - y2 = target[prefix + 'y'], - color = edge.color; - - if (!color) - switch (settings('edgeColor')) { - case 'source': - color = source.color || settings('defaultNodeColor'); - break; - case 'target': - color = target.color || settings('defaultNodeColor'); - break; - default: - color = settings('defaultEdgeColor'); - break; - } - - // Normalize color: - color = sigma.utils.floatColor(color); - - data[i++] = x1; - data[i++] = y1; - data[i++] = x2; - data[i++] = y2; - data[i++] = w; - data[i++] = 0.0; - data[i++] = color; - - data[i++] = x2; - data[i++] = y2; - data[i++] = x1; - data[i++] = y1; - data[i++] = w; - data[i++] = 1.0; - data[i++] = color; - - data[i++] = x2; - data[i++] = y2; - data[i++] = x1; - data[i++] = y1; - data[i++] = w; - data[i++] = 0.0; - data[i++] = color; - - data[i++] = x2; - data[i++] = y2; - data[i++] = x1; - data[i++] = y1; - data[i++] = w; - data[i++] = 0.0; - data[i++] = color; - - data[i++] = x1; - data[i++] = y1; - data[i++] = x2; - data[i++] = y2; - data[i++] = w; - data[i++] = 1.0; - data[i++] = color; - - data[i++] = x1; - data[i++] = y1; - data[i++] = x2; - data[i++] = y2; - data[i++] = w; - data[i++] = 0.0; - data[i++] = color; - }, - render: function(gl, program, data, params) { - var buffer; - - // Define attributes: - var colorLocation = - gl.getAttribLocation(program, 'a_color'), - positionLocation1 = - gl.getAttribLocation(program, 'a_position1'), - positionLocation2 = - gl.getAttribLocation(program, 'a_position2'), - thicknessLocation = - gl.getAttribLocation(program, 'a_thickness'), - minusLocation = - gl.getAttribLocation(program, 'a_minus'), - resolutionLocation = - gl.getUniformLocation(program, 'u_resolution'), - matrixLocation = - gl.getUniformLocation(program, 'u_matrix'), - matrixHalfPiLocation = - gl.getUniformLocation(program, 'u_matrixHalfPi'), - matrixHalfPiMinusLocation = - gl.getUniformLocation(program, 'u_matrixHalfPiMinus'), - ratioLocation = - gl.getUniformLocation(program, 'u_ratio'), - scaleLocation = - gl.getUniformLocation(program, 'u_scale'); - - buffer = gl.createBuffer(); - gl.bindBuffer(gl.ARRAY_BUFFER, buffer); - gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW); - - gl.uniform2f(resolutionLocation, params.width, params.height); - gl.uniform1f( - ratioLocation, - params.ratio / Math.pow(params.ratio, params.settings('edgesPowRatio')) - ); - gl.uniform1f(scaleLocation, params.scalingRatio); - gl.uniformMatrix3fv(matrixLocation, false, params.matrix); - gl.uniformMatrix2fv( - matrixHalfPiLocation, - false, - sigma.utils.matrices.rotation(Math.PI / 2, true) - ); - gl.uniformMatrix2fv( - matrixHalfPiMinusLocation, - false, - sigma.utils.matrices.rotation(-Math.PI / 2, true) - ); - - gl.enableVertexAttribArray(colorLocation); - gl.enableVertexAttribArray(positionLocation1); - gl.enableVertexAttribArray(positionLocation2); - gl.enableVertexAttribArray(thicknessLocation); - gl.enableVertexAttribArray(minusLocation); - - gl.vertexAttribPointer(positionLocation1, - 2, - gl.FLOAT, - false, - this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT, - 0 - ); - gl.vertexAttribPointer(positionLocation2, - 2, - gl.FLOAT, - false, - this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT, - 8 - ); - gl.vertexAttribPointer(thicknessLocation, - 1, - gl.FLOAT, - false, - this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT, - 16 - ); - gl.vertexAttribPointer(minusLocation, - 1, - gl.FLOAT, - false, - this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT, - 20 - ); - gl.vertexAttribPointer(colorLocation, - 1, - gl.FLOAT, - false, - this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT, - 24 - ); - - gl.drawArrays( - gl.TRIANGLES, - params.start || 0, - params.count || (data.length / this.ATTRIBUTES) - ); - }, - initProgram: function(gl) { - var vertexShader, - fragmentShader, - program; - - vertexShader = sigma.utils.loadShader( - gl, - [ - 'attribute vec2 a_position1;', - 'attribute vec2 a_position2;', - 'attribute float a_thickness;', - 'attribute float a_minus;', - 'attribute float a_color;', - - 'uniform vec2 u_resolution;', - 'uniform float u_ratio;', - 'uniform float u_scale;', - 'uniform mat3 u_matrix;', - 'uniform mat2 u_matrixHalfPi;', - 'uniform mat2 u_matrixHalfPiMinus;', - - 'varying vec4 color;', - - 'void main() {', - // Find the good point: - 'vec2 position = a_thickness * u_ratio *', - 'normalize(a_position2 - a_position1);', - - 'mat2 matrix = a_minus * u_matrixHalfPiMinus +', - '(1.0 - a_minus) * u_matrixHalfPi;', - - 'position = matrix * position + a_position1;', - - // Scale from [[-1 1] [-1 1]] to the container: - 'gl_Position = vec4(', - '((u_matrix * vec3(position, 1)).xy /', - 'u_resolution * 2.0 - 1.0) * vec2(1, -1),', - '0,', - '1', - ');', - - // Extract the color: - 'float c = a_color;', - 'color.b = mod(c, 256.0); c = floor(c / 256.0);', - 'color.g = mod(c, 256.0); c = floor(c / 256.0);', - 'color.r = mod(c, 256.0); c = floor(c / 256.0); color /= 255.0;', - 'color.a = 1.0;', - '}' - ].join('\n'), - gl.VERTEX_SHADER - ); - - fragmentShader = sigma.utils.loadShader( - gl, - [ - 'precision mediump float;', - - 'varying vec4 color;', - - 'void main(void) {', - 'gl_FragColor = color;', - '}' - ].join('\n'), - gl.FRAGMENT_SHADER - ); - - program = sigma.utils.loadProgram(gl, [vertexShader, fragmentShader]); - - return program; - } - }; -})(); diff --git a/src/demo/static/sigmajs/renderers/webgl/sigma.webgl.edges.fast.js b/src/demo/static/sigmajs/renderers/webgl/sigma.webgl.edges.fast.js deleted file mode 100644 index 48f56d76a..000000000 --- a/src/demo/static/sigmajs/renderers/webgl/sigma.webgl.edges.fast.js +++ /dev/null @@ -1,147 +0,0 @@ -;(function() { - 'use strict'; - - sigma.utils.pkg('sigma.webgl.edges'); - - /** - * This edge renderer will display edges as lines with the gl.LINES display - * mode. Since this mode does not support well thickness, edges are all drawn - * with the same thickness (3px), independantly of the edge attributes or the - * zooming ratio. - */ - sigma.webgl.edges.fast = { - POINTS: 2, - ATTRIBUTES: 3, - addEdge: function(edge, source, target, data, i, prefix, settings) { - var w = (edge[prefix + 'size'] || 1) / 2, - x1 = source[prefix + 'x'], - y1 = source[prefix + 'y'], - x2 = target[prefix + 'x'], - y2 = target[prefix + 'y'], - color = edge.color; - - if (!color) - switch (settings('edgeColor')) { - case 'source': - color = source.color || settings('defaultNodeColor'); - break; - case 'target': - color = target.color || settings('defaultNodeColor'); - break; - default: - color = settings('defaultEdgeColor'); - break; - } - - // Normalize color: - color = sigma.utils.floatColor(color); - - data[i++] = x1; - data[i++] = y1; - data[i++] = color; - - data[i++] = x2; - data[i++] = y2; - data[i++] = color; - }, - render: function(gl, program, data, params) { - var buffer; - - // Define attributes: - var colorLocation = - gl.getAttribLocation(program, 'a_color'), - positionLocation = - gl.getAttribLocation(program, 'a_position'), - resolutionLocation = - gl.getUniformLocation(program, 'u_resolution'), - matrixLocation = - gl.getUniformLocation(program, 'u_matrix'); - - buffer = gl.createBuffer(); - gl.bindBuffer(gl.ARRAY_BUFFER, buffer); - gl.bufferData(gl.ARRAY_BUFFER, data, gl.DYNAMIC_DRAW); - - gl.uniform2f(resolutionLocation, params.width, params.height); - gl.uniformMatrix3fv(matrixLocation, false, params.matrix); - - gl.enableVertexAttribArray(positionLocation); - gl.enableVertexAttribArray(colorLocation); - - gl.vertexAttribPointer(positionLocation, - 2, - gl.FLOAT, - false, - this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT, - 0 - ); - gl.vertexAttribPointer(colorLocation, - 1, - gl.FLOAT, - false, - this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT, - 8 - ); - - gl.lineWidth(3); - gl.drawArrays( - gl.LINES, - params.start || 0, - params.count || (data.length / this.ATTRIBUTES) - ); - }, - initProgram: function(gl) { - var vertexShader, - fragmentShader, - program; - - vertexShader = sigma.utils.loadShader( - gl, - [ - 'attribute vec2 a_position;', - 'attribute float a_color;', - - 'uniform vec2 u_resolution;', - 'uniform mat3 u_matrix;', - - 'varying vec4 color;', - - 'void main() {', - // Scale from [[-1 1] [-1 1]] to the container: - 'gl_Position = vec4(', - '((u_matrix * vec3(a_position, 1)).xy /', - 'u_resolution * 2.0 - 1.0) * vec2(1, -1),', - '0,', - '1', - ');', - - // Extract the color: - 'float c = a_color;', - 'color.b = mod(c, 256.0); c = floor(c / 256.0);', - 'color.g = mod(c, 256.0); c = floor(c / 256.0);', - 'color.r = mod(c, 256.0); c = floor(c / 256.0); color /= 255.0;', - 'color.a = 1.0;', - '}' - ].join('\n'), - gl.VERTEX_SHADER - ); - - fragmentShader = sigma.utils.loadShader( - gl, - [ - 'precision mediump float;', - - 'varying vec4 color;', - - 'void main(void) {', - 'gl_FragColor = color;', - '}' - ].join('\n'), - gl.FRAGMENT_SHADER - ); - - program = sigma.utils.loadProgram(gl, [vertexShader, fragmentShader]); - - return program; - } - }; -})(); diff --git a/src/demo/static/sigmajs/renderers/webgl/sigma.webgl.nodes.def.js b/src/demo/static/sigmajs/renderers/webgl/sigma.webgl.nodes.def.js deleted file mode 100644 index d16971353..000000000 --- a/src/demo/static/sigmajs/renderers/webgl/sigma.webgl.nodes.def.js +++ /dev/null @@ -1,201 +0,0 @@ -;(function() { - 'use strict'; - - sigma.utils.pkg('sigma.webgl.nodes'); - - /** - * This node renderer will display nodes as discs, shaped in triangles with - * the gl.TRIANGLES display mode. So, to be more precise, to draw one node, - * it will store three times the center of node, with the color and the size, - * and an angle indicating which "corner" of the triangle to draw. - * - * The fragment shader does not deal with anti-aliasing, so make sure that - * you deal with it somewhere else in the code (by default, the WebGL - * renderer will oversample the rendering through the webglOversamplingRatio - * value). - */ - sigma.webgl.nodes.def = { - POINTS: 3, - ATTRIBUTES: 5, - addNode: function(node, data, i, prefix, settings) { - var color = sigma.utils.floatColor( - node.color || settings('defaultNodeColor') - ); - - data[i++] = node[prefix + 'x']; - data[i++] = node[prefix + 'y']; - data[i++] = node[prefix + 'size']; - data[i++] = color; - data[i++] = 0; - - data[i++] = node[prefix + 'x']; - data[i++] = node[prefix + 'y']; - data[i++] = node[prefix + 'size']; - data[i++] = color; - data[i++] = 2 * Math.PI / 3; - - data[i++] = node[prefix + 'x']; - data[i++] = node[prefix + 'y']; - data[i++] = node[prefix + 'size']; - data[i++] = color; - data[i++] = 4 * Math.PI / 3; - }, - render: function(gl, program, data, params) { - var buffer; - - // Define attributes: - var positionLocation = - gl.getAttribLocation(program, 'a_position'), - sizeLocation = - gl.getAttribLocation(program, 'a_size'), - colorLocation = - gl.getAttribLocation(program, 'a_color'), - angleLocation = - gl.getAttribLocation(program, 'a_angle'), - resolutionLocation = - gl.getUniformLocation(program, 'u_resolution'), - matrixLocation = - gl.getUniformLocation(program, 'u_matrix'), - ratioLocation = - gl.getUniformLocation(program, 'u_ratio'), - scaleLocation = - gl.getUniformLocation(program, 'u_scale'); - - buffer = gl.createBuffer(); - gl.bindBuffer(gl.ARRAY_BUFFER, buffer); - gl.bufferData(gl.ARRAY_BUFFER, data, gl.DYNAMIC_DRAW); - - gl.uniform2f(resolutionLocation, params.width, params.height); - gl.uniform1f( - ratioLocation, - 1 / Math.pow(params.ratio, params.settings('nodesPowRatio')) - ); - gl.uniform1f(scaleLocation, params.scalingRatio); - gl.uniformMatrix3fv(matrixLocation, false, params.matrix); - - gl.enableVertexAttribArray(positionLocation); - gl.enableVertexAttribArray(sizeLocation); - gl.enableVertexAttribArray(colorLocation); - gl.enableVertexAttribArray(angleLocation); - - gl.vertexAttribPointer( - positionLocation, - 2, - gl.FLOAT, - false, - this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT, - 0 - ); - gl.vertexAttribPointer( - sizeLocation, - 1, - gl.FLOAT, - false, - this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT, - 8 - ); - gl.vertexAttribPointer( - colorLocation, - 1, - gl.FLOAT, - false, - this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT, - 12 - ); - gl.vertexAttribPointer( - angleLocation, - 1, - gl.FLOAT, - false, - this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT, - 16 - ); - - gl.drawArrays( - gl.TRIANGLES, - params.start || 0, - params.count || (data.length / this.ATTRIBUTES) - ); - }, - initProgram: function(gl) { - var vertexShader, - fragmentShader, - program; - - vertexShader = sigma.utils.loadShader( - gl, - [ - 'attribute vec2 a_position;', - 'attribute float a_size;', - 'attribute float a_color;', - 'attribute float a_angle;', - - 'uniform vec2 u_resolution;', - 'uniform float u_ratio;', - 'uniform float u_scale;', - 'uniform mat3 u_matrix;', - - 'varying vec4 color;', - 'varying vec2 center;', - 'varying float radius;', - - 'void main() {', - // Multiply the point size twice: - 'radius = a_size * u_ratio;', - - // Scale from [[-1 1] [-1 1]] to the container: - 'vec2 position = (u_matrix * vec3(a_position, 1)).xy;', - // 'center = (position / u_resolution * 2.0 - 1.0) * vec2(1, -1);', - 'center = position * u_scale;', - 'center = vec2(center.x, u_scale * u_resolution.y - center.y);', - - 'position = position +', - '2.0 * radius * vec2(cos(a_angle), sin(a_angle));', - 'position = (position / u_resolution * 2.0 - 1.0) * vec2(1, -1);', - - 'radius = radius * u_scale;', - - 'gl_Position = vec4(position, 0, 1);', - - // Extract the color: - 'float c = a_color;', - 'color.b = mod(c, 256.0); c = floor(c / 256.0);', - 'color.g = mod(c, 256.0); c = floor(c / 256.0);', - 'color.r = mod(c, 256.0); c = floor(c / 256.0); color /= 255.0;', - 'color.a = 1.0;', - '}' - ].join('\n'), - gl.VERTEX_SHADER - ); - - fragmentShader = sigma.utils.loadShader( - gl, - [ - 'precision mediump float;', - - 'varying vec4 color;', - 'varying vec2 center;', - 'varying float radius;', - - 'void main(void) {', - 'vec4 color0 = vec4(0.0, 0.0, 0.0, 0.0);', - - 'vec2 m = gl_FragCoord.xy - center;', - 'float diff = radius - sqrt(m.x * m.x + m.y * m.y);', - - // Here is how we draw a disc instead of a square: - 'if (diff > 0.0)', - 'gl_FragColor = color;', - 'else', - 'gl_FragColor = color0;', - '}' - ].join('\n'), - gl.FRAGMENT_SHADER - ); - - program = sigma.utils.loadProgram(gl, [vertexShader, fragmentShader]); - - return program; - } - }; -})(); diff --git a/src/demo/static/sigmajs/renderers/webgl/sigma.webgl.nodes.fast.js b/src/demo/static/sigmajs/renderers/webgl/sigma.webgl.nodes.fast.js deleted file mode 100644 index 3769fb698..000000000 --- a/src/demo/static/sigmajs/renderers/webgl/sigma.webgl.nodes.fast.js +++ /dev/null @@ -1,163 +0,0 @@ -;(function() { - 'use strict'; - - sigma.utils.pkg('sigma.webgl.nodes'); - - /** - * This node renderer will display nodes in the fastest way: Nodes are basic - * squares, drawn through the gl.POINTS drawing method. The size of the nodes - * are represented with the "gl_PointSize" value in the vertex shader. - * - * It is the fastest node renderer here since the buffer just takes one line - * to draw each node (with attributes "x", "y", "size" and "color"). - * - * Nevertheless, this method has some problems, especially due to some issues - * with the gl.POINTS: - * - First, if the center of a node is outside the scene, the point will not - * be drawn, even if it should be partly on screen. - * - I tried applying a fragment shader similar to the one in the default - * node renderer to display them as discs, but it did not work fine on - * some computers settings, filling the discs with weird gradients not - * depending on the actual color. - */ - sigma.webgl.nodes.fast = { - POINTS: 1, - ATTRIBUTES: 4, - addNode: function(node, data, i, prefix, settings) { - data[i++] = node[prefix + 'x']; - data[i++] = node[prefix + 'y']; - data[i++] = node[prefix + 'size']; - data[i++] = sigma.utils.floatColor( - node.color || settings('defaultNodeColor') - ); - }, - render: function(gl, program, data, params) { - var buffer; - - // Define attributes: - var positionLocation = - gl.getAttribLocation(program, 'a_position'), - sizeLocation = - gl.getAttribLocation(program, 'a_size'), - colorLocation = - gl.getAttribLocation(program, 'a_color'), - resolutionLocation = - gl.getUniformLocation(program, 'u_resolution'), - matrixLocation = - gl.getUniformLocation(program, 'u_matrix'), - ratioLocation = - gl.getUniformLocation(program, 'u_ratio'), - scaleLocation = - gl.getUniformLocation(program, 'u_scale'); - - buffer = gl.createBuffer(); - gl.bindBuffer(gl.ARRAY_BUFFER, buffer); - gl.bufferData(gl.ARRAY_BUFFER, data, gl.DYNAMIC_DRAW); - - gl.uniform2f(resolutionLocation, params.width, params.height); - gl.uniform1f( - ratioLocation, - 1 / Math.pow(params.ratio, params.settings('nodesPowRatio')) - ); - gl.uniform1f(scaleLocation, params.scalingRatio); - gl.uniformMatrix3fv(matrixLocation, false, params.matrix); - - gl.enableVertexAttribArray(positionLocation); - gl.enableVertexAttribArray(sizeLocation); - gl.enableVertexAttribArray(colorLocation); - - gl.vertexAttribPointer( - positionLocation, - 2, - gl.FLOAT, - false, - this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT, - 0 - ); - gl.vertexAttribPointer( - sizeLocation, - 1, - gl.FLOAT, - false, - this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT, - 8 - ); - gl.vertexAttribPointer( - colorLocation, - 1, - gl.FLOAT, - false, - this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT, - 12 - ); - - gl.drawArrays( - gl.POINTS, - params.start || 0, - params.count || (data.length / this.ATTRIBUTES) - ); - }, - initProgram: function(gl) { - var vertexShader, - fragmentShader, - program; - - vertexShader = sigma.utils.loadShader( - gl, - [ - 'attribute vec2 a_position;', - 'attribute float a_size;', - 'attribute float a_color;', - - 'uniform vec2 u_resolution;', - 'uniform float u_ratio;', - 'uniform float u_scale;', - 'uniform mat3 u_matrix;', - - 'varying vec4 color;', - - 'void main() {', - // Scale from [[-1 1] [-1 1]] to the container: - 'gl_Position = vec4(', - '((u_matrix * vec3(a_position, 1)).xy /', - 'u_resolution * 2.0 - 1.0) * vec2(1, -1),', - '0,', - '1', - ');', - - // Multiply the point size twice: - // - x SCALING_RATIO to correct the canvas scaling - // - x 2 to correct the formulae - 'gl_PointSize = a_size * u_ratio * u_scale * 2.0;', - - // Extract the color: - 'float c = a_color;', - 'color.b = mod(c, 256.0); c = floor(c / 256.0);', - 'color.g = mod(c, 256.0); c = floor(c / 256.0);', - 'color.r = mod(c, 256.0); c = floor(c / 256.0); color /= 255.0;', - 'color.a = 1.0;', - '}' - ].join('\n'), - gl.VERTEX_SHADER - ); - - fragmentShader = sigma.utils.loadShader( - gl, - [ - 'precision mediump float;', - - 'varying vec4 color;', - - 'void main(void) {', - 'gl_FragColor = color;', - '}' - ].join('\n'), - gl.FRAGMENT_SHADER - ); - - program = sigma.utils.loadProgram(gl, [vertexShader, fragmentShader]); - - return program; - } - }; -})(); diff --git a/src/demo/static/sigmajs/sigma.core.js b/src/demo/static/sigmajs/sigma.core.js deleted file mode 100644 index 4b77def21..000000000 --- a/src/demo/static/sigmajs/sigma.core.js +++ /dev/null @@ -1,739 +0,0 @@ -;(function(undefined) { - 'use strict'; - - var __instances = {}; - - /** - * This is the sigma instances constructor. One instance of sigma represent - * one graph. It is possible to represent this grapĥ with several renderers - * at the same time. By default, the default renderer (WebGL + Canvas - * polyfill) will be used as the only renderer, with the container specified - * in the configuration. - * - * @param {?*} conf The configuration of the instance. There are a lot of - * different recognized forms to instantiate sigma, check - * example files, documentation in this file and unit - * tests to know more. - * @return {sigma} The fresh new sigma instance. - * - * Instanciating sigma: - * ******************** - * If no parameter is given to the constructor, the instance will be created - * without any renderer or camera. It will just instantiate the graph, and - * other modules will have to be instantiated through the public methods, - * like "addRenderer" etc: - * - * > s0 = new sigma(); - * > s0.addRenderer({ - * > type: 'canvas', - * > container: 'my-container-id' - * > }); - * - * In most of the cases, sigma will simply be used with the default renderer. - * Then, since the only required parameter is the DOM container, there are - * some simpler way to call the constructor. The four following calls do the - * exact same things: - * - * > s1 = new sigma('my-container-id'); - * > s2 = new sigma(document.getElementById('my-container-id')); - * > s3 = new sigma({ - * > container: document.getElementById('my-container-id') - * > }); - * > s4 = new sigma({ - * > renderers: [{ - * > container: document.getElementById('my-container-id') - * > }] - * > }); - * - * Recognized parameters: - * ********************** - * Here is the exhaustive list of every accepted parameters, when calling the - * constructor with to top level configuration object (fourth case in the - * previous examples): - * - * {?string} id The id of the instance. It will be generated - * automatically if not specified. - * {?array} renderers An array containing objects describing renderers. - * {?object} graph An object containing an array of nodes and an array - * of edges, to avoid having to add them by hand later. - * {?object} settings An object containing instance specific settings that - * will override the default ones defined in the object - * sigma.settings. - */ - var sigma = function(conf) { - // Local variables: - // **************** - var i, - l, - a, - c, - o, - id; - - sigma.classes.dispatcher.extend(this); - - // Private attributes: - // ******************* - var _self = this, - _conf = conf || {}; - - // Little shortcut: - // **************** - // The configuration is supposed to have a list of the configuration - // objects for each renderer. - // - If there are no configuration at all, then nothing is done. - // - If there are no renderer list, the given configuration object will be - // considered as describing the first and only renderer. - // - If there are no renderer list nor "container" object, it will be - // considered as the container itself (a DOM element). - // - If the argument passed to sigma() is a string, it will be considered - // as the ID of the DOM container. - if ( - typeof _conf === 'string' || - _conf instanceof HTMLElement - ) - _conf = { - renderers: [_conf] - }; - else if (Object.prototype.toString.call(_conf) === '[object Array]') - _conf = { - renderers: _conf - }; - - // Also check "renderer" and "container" keys: - o = _conf.renderers || _conf.renderer || _conf.container; - if (!_conf.renderers || _conf.renderers.length === 0) - if ( - typeof o === 'string' || - o instanceof HTMLElement || - (typeof o === 'object' && 'container' in o) - ) - _conf.renderers = [o]; - - // Recense the instance: - if (_conf.id) { - if (__instances[_conf.id]) - throw 'sigma: Instance "' + _conf.id + '" already exists.'; - Object.defineProperty(this, 'id', { - value: _conf.id - }); - } else { - id = 0; - while (__instances[id]) - id++; - Object.defineProperty(this, 'id', { - value: '' + id - }); - } - __instances[this.id] = this; - - // Initialize settings function: - this.settings = new sigma.classes.configurable( - sigma.settings, - _conf.settings || {} - ); - - // Initialize locked attributes: - Object.defineProperty(this, 'graph', { - value: new sigma.classes.graph(this.settings), - configurable: true - }); - Object.defineProperty(this, 'middlewares', { - value: [], - configurable: true - }); - Object.defineProperty(this, 'cameras', { - value: {}, - configurable: true - }); - Object.defineProperty(this, 'renderers', { - value: {}, - configurable: true - }); - Object.defineProperty(this, 'renderersPerCamera', { - value: {}, - configurable: true - }); - Object.defineProperty(this, 'cameraFrames', { - value: {}, - configurable: true - }); - Object.defineProperty(this, 'camera', { - get: function() { - return this.cameras[0]; - } - }); - Object.defineProperty(this, 'events', { - value: [ - 'click', - 'rightClick', - 'clickStage', - 'doubleClickStage', - 'rightClickStage', - 'clickNode', - 'clickNodes', - 'doubleClickNode', - 'doubleClickNodes', - 'rightClickNode', - 'rightClickNodes', - 'overNode', - 'overNodes', - 'outNode', - 'outNodes', - 'downNode', - 'downNodes', - 'upNode', - 'upNodes' - ], - configurable: true - }); - - // Add a custom handler, to redispatch events from renderers: - this._handler = (function(e) { - var k, - data = {}; - - for (k in e.data) - data[k] = e.data[k]; - - data.renderer = e.target; - this.dispatchEvent(e.type, data); - }).bind(this); - - // Initialize renderers: - a = _conf.renderers || []; - for (i = 0, l = a.length; i < l; i++) - this.addRenderer(a[i]); - - // Initialize middlewares: - a = _conf.middlewares || []; - for (i = 0, l = a.length; i < l; i++) - this.middlewares.push( - typeof a[i] === 'string' ? - sigma.middlewares[a[i]] : - a[i] - ); - - // Check if there is already a graph to fill in: - if (typeof _conf.graph === 'object' && _conf.graph) { - this.graph.read(_conf.graph); - - // If a graph is given to the to the instance, the "refresh" method is - // directly called: - this.refresh(); - } - - // Deal with resize: - window.addEventListener('resize', function() { - if (_self.settings) - _self.refresh(); - }); - }; - - - - - /** - * This methods will instantiate and reference a new camera. If no id is - * specified, then an automatic id will be generated. - * - * @param {?string} id Eventually the camera id. - * @return {sigma.classes.camera} The fresh new camera instance. - */ - sigma.prototype.addCamera = function(id) { - var self = this, - camera; - - if (!arguments.length) { - id = 0; - while (this.cameras['' + id]) - id++; - id = '' + id; - } - - if (this.cameras[id]) - throw 'sigma.addCamera: The camera "' + id + '" already exists.'; - - camera = new sigma.classes.camera(id, this.graph, this.settings); - this.cameras[id] = camera; - - // Add a quadtree to the camera: - camera.quadtree = new sigma.classes.quad(); - - // Add an edgequadtree to the camera: - if (sigma.classes.edgequad !== undefined) { - camera.edgequadtree = new sigma.classes.edgequad(); - } - - camera.bind('coordinatesUpdated', function(e) { - self.renderCamera(camera, camera.isAnimated); - }); - - this.renderersPerCamera[id] = []; - - return camera; - }; - - /** - * This method kills a camera, and every renderer attached to it. - * - * @param {string|camera} v The camera to kill or its ID. - * @return {sigma} Returns the instance. - */ - sigma.prototype.killCamera = function(v) { - v = typeof v === 'string' ? this.cameras[v] : v; - - if (!v) - throw 'sigma.killCamera: The camera is undefined.'; - - var i, - l, - a = this.renderersPerCamera[v.id]; - - for (l = a.length, i = l - 1; i >= 0; i--) - this.killRenderer(a[i]); - - delete this.renderersPerCamera[v.id]; - delete this.cameraFrames[v.id]; - delete this.cameras[v.id]; - - if (v.kill) - v.kill(); - - return this; - }; - - /** - * This methods will instantiate and reference a new renderer. The "type" - * argument can be the constructor or its name in the "sigma.renderers" - * package. If no type is specified, then "sigma.renderers.def" will be used. - * If no id is specified, then an automatic id will be generated. - * - * @param {?object} options Eventually some options to give to the renderer - * constructor. - * @return {renderer} The fresh new renderer instance. - * - * Recognized parameters: - * ********************** - * Here is the exhaustive list of every accepted parameters in the "options" - * object: - * - * {?string} id Eventually the renderer id. - * {?(function|string)} type Eventually the renderer constructor or its - * name in the "sigma.renderers" package. - * {?(camera|string)} camera Eventually the renderer camera or its - * id. - */ - sigma.prototype.addRenderer = function(options) { - var id, - fn, - camera, - renderer, - o = options || {}; - - // Polymorphism: - if (typeof o === 'string') - o = { - container: document.getElementById(o) - }; - else if (o instanceof HTMLElement) - o = { - container: o - }; - - // If the container still is a string, we get it by id - if (typeof o.container === 'string') - o.container = document.getElementById(o.container); - - // Reference the new renderer: - if (!('id' in o)) { - id = 0; - while (this.renderers['' + id]) - id++; - id = '' + id; - } else - id = o.id; - - if (this.renderers[id]) - throw 'sigma.addRenderer: The renderer "' + id + '" already exists.'; - - // Find the good constructor: - fn = typeof o.type === 'function' ? o.type : sigma.renderers[o.type]; - fn = fn || sigma.renderers.def; - - // Find the good camera: - camera = 'camera' in o ? - ( - o.camera instanceof sigma.classes.camera ? - o.camera : - this.cameras[o.camera] || this.addCamera(o.camera) - ) : - this.addCamera(); - - if (this.cameras[camera.id] !== camera) - throw 'sigma.addRenderer: The camera is not properly referenced.'; - - // Instantiate: - renderer = new fn(this.graph, camera, this.settings, o); - this.renderers[id] = renderer; - Object.defineProperty(renderer, 'id', { - value: id - }); - - // Bind events: - if (renderer.bind) - renderer.bind( - [ - 'click', - 'rightClick', - 'clickStage', - 'doubleClickStage', - 'rightClickStage', - 'clickNode', - 'clickNodes', - 'clickEdge', - 'clickEdges', - 'doubleClickNode', - 'doubleClickNodes', - 'doubleClickEdge', - 'doubleClickEdges', - 'rightClickNode', - 'rightClickNodes', - 'rightClickEdge', - 'rightClickEdges', - 'overNode', - 'overNodes', - 'overEdge', - 'overEdges', - 'outNode', - 'outNodes', - 'outEdge', - 'outEdges', - 'downNode', - 'downNodes', - 'downEdge', - 'downEdges', - 'upNode', - 'upNodes', - 'upEdge', - 'upEdges' - ], - this._handler - ); - - // Reference the renderer by its camera: - this.renderersPerCamera[camera.id].push(renderer); - - return renderer; - }; - - /** - * This method kills a renderer. - * - * @param {string|renderer} v The renderer to kill or its ID. - * @return {sigma} Returns the instance. - */ - sigma.prototype.killRenderer = function(v) { - v = typeof v === 'string' ? this.renderers[v] : v; - - if (!v) - throw 'sigma.killRenderer: The renderer is undefined.'; - - var a = this.renderersPerCamera[v.camera.id], - i = a.indexOf(v); - - if (i >= 0) - a.splice(i, 1); - - if (v.kill) - v.kill(); - - delete this.renderers[v.id]; - - return this; - }; - - - - - /** - * This method calls the "render" method of each renderer, with the same - * arguments than the "render" method, but will also check if the renderer - * has a "process" method, and call it if it exists. - * - * It is useful for quadtrees or WebGL processing, for instance. - * - * @param {?object} options Eventually some options to give to the refresh - * method. - * @return {sigma} Returns the instance itself. - * - * Recognized parameters: - * ********************** - * Here is the exhaustive list of every accepted parameters in the "options" - * object: - * - * {?boolean} skipIndexation A flag specifying wether or not the refresh - * function should reindex the graph in the - * quadtrees or not (default: false). - */ - sigma.prototype.refresh = function(options) { - var i, - l, - k, - a, - c, - bounds, - prefix = 0; - - options = options || {}; - - // Call each middleware: - a = this.middlewares || []; - for (i = 0, l = a.length; i < l; i++) - a[i].call( - this, - (i === 0) ? '' : 'tmp' + prefix + ':', - (i === l - 1) ? 'ready:' : ('tmp' + (++prefix) + ':') - ); - - // Then, for each camera, call the "rescale" middleware, unless the - // settings specify not to: - for (k in this.cameras) { - c = this.cameras[k]; - if ( - c.settings('autoRescale') && - this.renderersPerCamera[c.id] && - this.renderersPerCamera[c.id].length - ) - sigma.middlewares.rescale.call( - this, - a.length ? 'ready:' : '', - c.readPrefix, - { - width: this.renderersPerCamera[c.id][0].width, - height: this.renderersPerCamera[c.id][0].height - } - ); - else - sigma.middlewares.copy.call( - this, - a.length ? 'ready:' : '', - c.readPrefix - ); - - if (!options.skipIndexation) { - // Find graph boundaries: - bounds = sigma.utils.getBoundaries( - this.graph, - c.readPrefix - ); - - // Refresh quadtree: - c.quadtree.index(this.graph.nodes(), { - prefix: c.readPrefix, - bounds: { - x: bounds.minX, - y: bounds.minY, - width: bounds.maxX - bounds.minX, - height: bounds.maxY - bounds.minY - } - }); - - // Refresh edgequadtree: - if ( - c.edgequadtree !== undefined && - c.settings('drawEdges') && - c.settings('enableEdgeHovering') - ) { - c.edgequadtree.index(this.graph, { - prefix: c.readPrefix, - bounds: { - x: bounds.minX, - y: bounds.minY, - width: bounds.maxX - bounds.minX, - height: bounds.maxY - bounds.minY - } - }); - } - } - } - - // Call each renderer: - a = Object.keys(this.renderers); - for (i = 0, l = a.length; i < l; i++) - if (this.renderers[a[i]].process) { - if (this.settings('skipErrors')) - try { - this.renderers[a[i]].process(); - } catch (e) { - console.log( - 'Warning: The renderer "' + a[i] + '" crashed on ".process()"' - ); - } - else - this.renderers[a[i]].process(); - } - - this.render(); - - return this; - }; - - /** - * This method calls the "render" method of each renderer. - * - * @return {sigma} Returns the instance itself. - */ - sigma.prototype.render = function() { - var i, - l, - a, - prefix = 0; - - // Call each renderer: - a = Object.keys(this.renderers); - for (i = 0, l = a.length; i < l; i++) - if (this.settings('skipErrors')) - try { - this.renderers[a[i]].render(); - } catch (e) { - if (this.settings('verbose')) - console.log( - 'Warning: The renderer "' + a[i] + '" crashed on ".render()"' - ); - } - else - this.renderers[a[i]].render(); - - return this; - }; - - /** - * This method calls the "render" method of each renderer that is bound to - * the specified camera. To improve the performances, if this method is - * called too often, the number of effective renderings is limitated to one - * per frame, unless you are using the "force" flag. - * - * @param {sigma.classes.camera} camera The camera to render. - * @param {?boolean} force If true, will render the camera - * directly. - * @return {sigma} Returns the instance itself. - */ - sigma.prototype.renderCamera = function(camera, force) { - var i, - l, - a, - self = this; - - if (force) { - a = this.renderersPerCamera[camera.id]; - for (i = 0, l = a.length; i < l; i++) - if (this.settings('skipErrors')) - try { - a[i].render(); - } catch (e) { - if (this.settings('verbose')) - console.log( - 'Warning: The renderer "' + a[i].id + '" crashed on ".render()"' - ); - } - else - a[i].render(); - } else { - if (!this.cameraFrames[camera.id]) { - a = this.renderersPerCamera[camera.id]; - for (i = 0, l = a.length; i < l; i++) - if (this.settings('skipErrors')) - try { - a[i].render(); - } catch (e) { - if (this.settings('verbose')) - console.log( - 'Warning: The renderer "' + - a[i].id + - '" crashed on ".render()"' - ); - } - else - a[i].render(); - - this.cameraFrames[camera.id] = requestAnimationFrame(function() { - delete self.cameraFrames[camera.id]; - }); - } - } - - return this; - }; - - /** - * This method calls the "kill" method of each module and destroys any - * reference from the instance. - */ - sigma.prototype.kill = function() { - var k; - - // Dispatching event - this.dispatchEvent('kill'); - - // Kill graph: - this.graph.kill(); - - // Kill middlewares: - delete this.middlewares; - - // Kill each renderer: - for (k in this.renderers) - this.killRenderer(this.renderers[k]); - - // Kill each camera: - for (k in this.cameras) - this.killCamera(this.cameras[k]); - - delete this.renderers; - delete this.cameras; - - // Kill everything else: - for (k in this) - if (this.hasOwnProperty(k)) - delete this[k]; - - delete __instances[this.id]; - }; - - - - - /** - * Returns a clone of the instances object or a specific running instance. - * - * @param {?string} id Eventually an instance ID. - * @return {object} The related instance or a clone of the instances - * object. - */ - sigma.instances = function(id) { - return arguments.length ? - __instances[id] : - sigma.utils.extend({}, __instances); - }; - - - - /** - * The current version of sigma: - */ - sigma.version = '1.0.3'; - - - - - /** - * EXPORT: - * ******* - */ - if (typeof this.sigma !== 'undefined') - throw 'An object called sigma is already in the global scope.'; - - this.sigma = sigma; - -}).call(this); diff --git a/src/demo/static/sigmajs/sigma.export.js b/src/demo/static/sigmajs/sigma.export.js deleted file mode 100644 index ff9e7856a..000000000 --- a/src/demo/static/sigmajs/sigma.export.js +++ /dev/null @@ -1,20 +0,0 @@ -// Hardcoded export for the node.js version: -var sigma = this.sigma, - conrad = this.conrad; - -sigma.conrad = conrad; - -// Dirty polyfills to permit sigma usage in node -if (HTMLElement === undefined) - var HTMLElement = function() {}; - -if (window === undefined) - var window = { - addEventListener: function() {} - }; - -if (typeof exports !== 'undefined') { - if (typeof module !== 'undefined' && module.exports) - exports = module.exports = sigma; - exports.sigma = sigma; -} diff --git a/src/demo/static/sigmajs/sigma.settings.js b/src/demo/static/sigmajs/sigma.settings.js deleted file mode 100644 index cee34b885..000000000 --- a/src/demo/static/sigmajs/sigma.settings.js +++ /dev/null @@ -1,251 +0,0 @@ -;(function(undefined) { - 'use strict'; - - if (typeof sigma === 'undefined') - throw 'sigma is not declared'; - - // Packages initialization: - sigma.utils.pkg('sigma.settings'); - - var settings = { - /** - * GRAPH SETTINGS: - * *************** - */ - // {boolean} Indicates if the data have to be cloned in methods to add - // nodes or edges. - clone: true, - // {boolean} Indicates if nodes "id" values and edges "id", "source" and - // "target" values must be set as immutable. - immutable: true, - // {boolean} Indicates if sigma can log its errors and warnings. - verbose: false, - - - /** - * RENDERERS SETTINGS: - * ******************* - */ - // {string} - classPrefix: 'sigma', - // {string} - defaultNodeType: 'def', - // {string} - defaultEdgeType: 'def', - // {string} - defaultLabelColor: '#000', - // {string} - defaultEdgeColor: '#000', - // {string} - defaultNodeColor: '#000', - // {string} - defaultLabelSize: 14, - // {string} Indicates how to choose the edges color. Available values: - // "source", "target", "default" - edgeColor: 'source', - // {number} Defines the minimal edge's arrow display size. - minArrowSize: 0, - // {string} - font: 'arial', - // {string} Example: 'bold' - fontStyle: '', - // {string} Indicates how to choose the labels color. Available values: - // "node", "default" - labelColor: 'default', - // {string} Indicates how to choose the labels size. Available values: - // "fixed", "proportional" - labelSize: 'fixed', - // {string} The ratio between the font size of the label and the node size. - labelSizeRatio: 1, - // {number} The minimum size a node must have to see its label displayed. - labelThreshold: 8, - // {number} The oversampling factor used in WebGL renderer. - webglOversamplingRatio: 2, - // {number} The size of the border of hovered nodes. - borderSize: 0, - // {number} The default hovered node border's color. - defaultNodeBorderColor: '#000', - // {number} The hovered node's label font. If not specified, will heritate - // the "font" value. - hoverFont: '', - // {boolean} If true, then only one node can be hovered at a time. - singleHover: true, - // {string} Example: 'bold' - hoverFontStyle: '', - // {string} Indicates how to choose the hovered nodes shadow color. - // Available values: "node", "default" - labelHoverShadow: 'default', - // {string} - labelHoverShadowColor: '#000', - // {string} Indicates how to choose the hovered nodes color. - // Available values: "node", "default" - nodeHoverColor: 'node', - // {string} - defaultNodeHoverColor: '#000', - // {string} Indicates how to choose the hovered nodes background color. - // Available values: "node", "default" - labelHoverBGColor: 'default', - // {string} - defaultHoverLabelBGColor: '#fff', - // {string} Indicates how to choose the hovered labels color. - // Available values: "node", "default" - labelHoverColor: 'default', - // {string} - defaultLabelHoverColor: '#000', - // {string} Indicates how to choose the edges hover color. Available values: - // "edge", "default" - edgeHoverColor: 'edge', - // {number} The size multiplicator of hovered edges. - edgeHoverSizeRatio: 1, - // {string} - defaultEdgeHoverColor: '#000', - // {boolean} Indicates if the edge extremities must be hovered when the - // edge is hovered. - edgeHoverExtremities: false, - // {booleans} The different drawing modes: - // false: Layered not displayed. - // true: Layered displayed. - drawEdges: true, - drawNodes: true, - drawLabels: true, - drawEdgeLabels: false, - // {boolean} Indicates if the edges must be drawn in several frames or in - // one frame, as the nodes and labels are drawn. - batchEdgesDrawing: false, - // {boolean} Indicates if the edges must be hidden during dragging and - // animations. - hideEdgesOnMove: false, - // {numbers} The different batch sizes, when elements are displayed in - // several frames. - canvasEdgesBatchSize: 500, - webglEdgesBatchSize: 1000, - - - - - /** - * RESCALE SETTINGS: - * ***************** - */ - // {string} Indicates of to scale the graph relatively to its container. - // Available values: "inside", "outside" - scalingMode: 'inside', - // {number} The margin to keep around the graph. - sideMargin: 0, - // {number} Determine the size of the smallest and the biggest node / edges - // on the screen. This mapping makes easier to display the graph, - // avoiding too big nodes that take half of the screen, or too - // small ones that are not readable. If the two parameters are - // equals, then the minimal display size will be 0. And if they - // are both equal to 0, then there is no mapping, and the radius - // of the nodes will be their size. - minEdgeSize: 0.5, - maxEdgeSize: 1, - minNodeSize: 1, - maxNodeSize: 8, - - - - - /** - * CAPTORS SETTINGS: - * ***************** - */ - // {boolean} - touchEnabled: true, - // {boolean} - mouseEnabled: true, - // {boolean} - mouseWheelEnabled: true, - // {boolean} - doubleClickEnabled: true, - // {boolean} Defines whether the custom events such as "clickNode" can be - // used. - eventsEnabled: true, - // {number} Defines by how much multiplicating the zooming level when the - // user zooms with the mouse-wheel. - zoomingRatio: 1.7, - // {number} Defines by how much multiplicating the zooming level when the - // user zooms by double clicking. - doubleClickZoomingRatio: 2.2, - // {number} The minimum zooming level. - zoomMin: 0.0625, - // {number} The maximum zooming level. - zoomMax: 2, - // {number} The duration of animations following a mouse scrolling. - mouseZoomDuration: 200, - // {number} The duration of animations following a mouse double click. - doubleClickZoomDuration: 200, - // {number} The duration of animations following a mouse dropping. - mouseInertiaDuration: 200, - // {number} The inertia power (mouse captor). - mouseInertiaRatio: 3, - // {number} The duration of animations following a touch dropping. - touchInertiaDuration: 200, - // {number} The inertia power (touch captor). - touchInertiaRatio: 3, - // {number} The maximum time between two clicks to make it a double click. - doubleClickTimeout: 300, - // {number} The maximum time between two taps to make it a double tap. - doubleTapTimeout: 300, - // {number} The maximum time of dragging to trigger intertia. - dragTimeout: 200, - - - - - /** - * GLOBAL SETTINGS: - * **************** - */ - // {boolean} Determines whether the instance has to refresh itself - // automatically when a "resize" event is dispatched from the - // window object. - autoResize: true, - // {boolean} Determines whether the "rescale" middleware has to be called - // automatically for each camera on refresh. - autoRescale: true, - // {boolean} If set to false, the camera method "goTo" will basically do - // nothing. - enableCamera: true, - // {boolean} If set to false, the nodes cannot be hovered. - enableHovering: true, - // {boolean} If set to true, the edges can be hovered. - enableEdgeHovering: false, - // {number} The size of the area around the edges to activate hovering. - edgeHoverPrecision: 5, - // {boolean} If set to true, the rescale middleware will ignore node sizes - // to determine the graphs boundings. - rescaleIgnoreSize: false, - // {boolean} Determines if the core has to try to catch errors on - // rendering. - skipErrors: false, - - - - - /** - * CAMERA SETTINGS: - * **************** - */ - // {number} The power degrees applied to the nodes/edges size relatively to - // the zooming level. Basically: - // > onScreenR = Math.pow(zoom, nodesPowRatio) * R - // > onScreenT = Math.pow(zoom, edgesPowRatio) * T - nodesPowRatio: 0.5, - edgesPowRatio: 0.5, - - - - - /** - * ANIMATIONS SETTINGS: - * ******************** - */ - // {number} The default animation time. - animationsTime: 200 - }; - - // Export the previously designed settings: - sigma.settings = sigma.utils.extend(sigma.settings || {}, settings); -}).call(this); diff --git a/src/demo/static/sigmajs/utils/sigma.polyfills.js b/src/demo/static/sigmajs/utils/sigma.polyfills.js deleted file mode 100644 index 459b94382..000000000 --- a/src/demo/static/sigmajs/utils/sigma.polyfills.js +++ /dev/null @@ -1,77 +0,0 @@ -;(function(global) { - 'use strict'; - - /** - * http://paulirish.com/2011/requestanimationframe-for-smart-animating/ - * http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating - * requestAnimationFrame polyfill by Erik Möller. - * fixes from Paul Irish and Tino Zijdel - * MIT license - */ - var x, - lastTime = 0, - vendors = ['ms', 'moz', 'webkit', 'o']; - - for (x = 0; x < vendors.length && !global.requestAnimationFrame; x++) { - global.requestAnimationFrame = - global[vendors[x] + 'RequestAnimationFrame']; - global.cancelAnimationFrame = - global[vendors[x] + 'CancelAnimationFrame'] || - global[vendors[x] + 'CancelRequestAnimationFrame']; - } - - if (!global.requestAnimationFrame) - global.requestAnimationFrame = function(callback, element) { - var currTime = new Date().getTime(), - timeToCall = Math.max(0, 16 - (currTime - lastTime)), - id = global.setTimeout( - function() { - callback(currTime + timeToCall); - }, - timeToCall - ); - - lastTime = currTime + timeToCall; - return id; - }; - - if (!global.cancelAnimationFrame) - global.cancelAnimationFrame = function(id) { - clearTimeout(id); - }; - - /** - * Function.prototype.bind polyfill found on MDN. - * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind#Compatibility - * Public domain - */ - if (!Function.prototype.bind) - Function.prototype.bind = function(oThis) { - if (typeof this !== 'function') - // Closest thing possible to the ECMAScript 5 internal IsCallable - // function: - throw new TypeError( - 'Function.prototype.bind - what is trying to be bound is not callable' - ); - - var aArgs = Array.prototype.slice.call(arguments, 1), - fToBind = this, - fNOP, - fBound; - - fNOP = function() {}; - fBound = function() { - return fToBind.apply( - this instanceof fNOP && oThis ? - this : - oThis, - aArgs.concat(Array.prototype.slice.call(arguments)) - ); - }; - - fNOP.prototype = this.prototype; - fBound.prototype = new fNOP(); - - return fBound; - }; -})(this); diff --git a/src/demo/static/sigmajs/utils/sigma.utils.js b/src/demo/static/sigmajs/utils/sigma.utils.js deleted file mode 100644 index fd0f59b5d..000000000 --- a/src/demo/static/sigmajs/utils/sigma.utils.js +++ /dev/null @@ -1,950 +0,0 @@ -;(function(undefined) { - 'use strict'; - - if (typeof sigma === 'undefined') - throw 'sigma is not declared'; - - var _root = this; - - // Initialize packages: - sigma.utils = sigma.utils || {}; - - /** - * MISC UTILS: - */ - /** - * This function takes any number of objects as arguments, copies from each - * of these objects each pair key/value into a new object, and finally - * returns this object. - * - * The arguments are parsed from the last one to the first one, such that - * when several objects have keys in common, the "earliest" object wins. - * - * Example: - * ******** - * > var o1 = { - * > a: 1, - * > b: 2, - * > c: '3' - * > }, - * > o2 = { - * > c: '4', - * > d: [ 5 ] - * > }; - * > sigma.utils.extend(o1, o2); - * > // Returns: { - * > // a: 1, - * > // b: 2, - * > // c: '3', - * > // d: [ 5 ] - * > // }; - * - * @param {object+} Any number of objects. - * @return {object} The merged object. - */ - sigma.utils.extend = function() { - var i, - k, - res = {}, - l = arguments.length; - - for (i = l - 1; i >= 0; i--) - for (k in arguments[i]) - res[k] = arguments[i][k]; - - return res; - }; - - /** - * A short "Date.now()" polyfill. - * - * @return {Number} The current time (in ms). - */ - sigma.utils.dateNow = function() { - return Date.now ? Date.now() : new Date().getTime(); - }; - - /** - * Takes a package name as parameter and checks at each lebel if it exists, - * and if it does not, creates it. - * - * Example: - * ******** - * > sigma.utils.pkg('a.b.c'); - * > a.b.c; - * > // Object {}; - * > - * > sigma.utils.pkg('a.b.d'); - * > a.b; - * > // Object { c: {}, d: {} }; - * - * @param {string} pkgName The name of the package to create/find. - * @return {object} The related package. - */ - sigma.utils.pkg = function(pkgName) { - return (pkgName || '').split('.').reduce(function(context, objName) { - return (objName in context) ? - context[objName] : - (context[objName] = {}); - }, _root); - }; - - /** - * Returns a unique incremental number ID. - * - * Example: - * ******** - * > sigma.utils.id(); - * > // 1; - * > - * > sigma.utils.id(); - * > // 2; - * > - * > sigma.utils.id(); - * > // 3; - * - * @param {string} pkgName The name of the package to create/find. - * @return {object} The related package. - */ - sigma.utils.id = (function() { - var i = 0; - return function() { - return ++i; - }; - })(); - - /** - * This function takes an hexa color (for instance "#ffcc00" or "#fc0") or a - * rgb / rgba color (like "rgb(255,255,12)" or "rgba(255,255,12,1)") and - * returns an integer equal to "r * 255 * 255 + g * 255 + b", to gain some - * memory in the data given to WebGL shaders. - * - * @param {string} val The hexa or rgba color. - * @return {number} The number value. - */ - sigma.utils.floatColor = function(val) { - var result = [0, 0, 0]; - - if (val.match(/^#/)) { - val = (val || '').replace(/^#/, ''); - result = (val.length === 3) ? - [ - parseInt(val.charAt(0) + val.charAt(0), 16), - parseInt(val.charAt(1) + val.charAt(1), 16), - parseInt(val.charAt(2) + val.charAt(2), 16) - ] : - [ - parseInt(val.charAt(0) + val.charAt(1), 16), - parseInt(val.charAt(2) + val.charAt(3), 16), - parseInt(val.charAt(4) + val.charAt(5), 16) - ]; - } else if (val.match(/^ *rgba? *\(/)) { - val = val.match( - /^ *rgba? *\( *([0-9]*) *, *([0-9]*) *, *([0-9]*) *(,.*)?\) *$/ - ); - result = [ - +val[1], - +val[2], - +val[3] - ]; - } - - return ( - result[0] * 256 * 256 + - result[1] * 256 + - result[2] - ); - }; - - /** - * Perform a zoom into a camera, with or without animation, to the - * coordinates indicated using a specified ratio. - * - * Recognized parameters: - * ********************** - * Here is the exhaustive list of every accepted parameters in the animation - * object: - * - * {?number} duration An amount of time that means the duration of the - * animation. If this parameter doesn't exist the - * zoom will be performed without animation. - * {?function} onComplete A function to perform it after the animation. It - * will be performed even if there is no duration. - * - * @param {camera} The camera where perform the zoom. - * @param {x} The X coordiantion where the zoom goes. - * @param {y} The Y coordiantion where the zoom goes. - * @param {ratio} The ratio to apply it to the current camera ratio. - * @param {?animation} A dictionary with options for a possible animation. - */ - sigma.utils.zoomTo = function(camera, x, y, ratio, animation) { - var settings = camera.settings, - count, - newRatio, - animationSettings, - coordinates; - - // Create the newRatio dealing with min / max: - newRatio = Math.max( - settings('zoomMin'), - Math.min( - settings('zoomMax'), - camera.ratio * ratio - ) - ); - - // Check that the new ratio is different from the initial one: - if (newRatio !== camera.ratio) { - // Create the coordinates variable: - ratio = newRatio / camera.ratio; - coordinates = { - x: x * (1 - ratio) + camera.x, - y: y * (1 - ratio) + camera.y, - ratio: newRatio - }; - - if (animation && animation.duration) { - // Complete the animation setings: - count = sigma.misc.animation.killAll(camera); - animation = sigma.utils.extend( - animation, - { - easing: count ? 'quadraticOut' : 'quadraticInOut' - } - ); - - sigma.misc.animation.camera(camera, coordinates, animation); - } else { - camera.goTo(coordinates); - if (animation && animation.onComplete) - animation.onComplete(); - } - } - }; - - /** - * Return the control point coordinates for a quadratic bezier curve. - * - * @param {number} x1 The X coordinate of the start point. - * @param {number} y1 The Y coordinate of the start point. - * @param {number} x2 The X coordinate of the end point. - * @param {number} y2 The Y coordinate of the end point. - * @return {x,y} The control point coordinates. - */ - sigma.utils.getQuadraticControlPoint = function(x1, y1, x2, y2) { - return { - x: (x1 + x2) / 2 + (y2 - y1) / 4, - y: (y1 + y2) / 2 + (x1 - x2) / 4 - }; - }; - - /** - * Compute the coordinates of the point positioned - * at length t in the quadratic bezier curve. - * - * @param {number} t In [0,1] the step percentage to reach - * the point in the curve from the context point. - * @param {number} x1 The X coordinate of the context point. - * @param {number} y1 The Y coordinate of the context point. - * @param {number} x2 The X coordinate of the ending point. - * @param {number} y2 The Y coordinate of the ending point. - * @param {number} xi The X coordinate of the control point. - * @param {number} yi The Y coordinate of the control point. - * @return {object} {x,y}. - */ - sigma.utils.getPointOnQuadraticCurve = function(t, x1, y1, x2, y2, xi, yi) { - // http://stackoverflow.com/a/5634528 - return { - x: Math.pow(1 - t, 2) * x1 + 2 * (1 - t) * t * xi + Math.pow(t, 2) * x2, - y: Math.pow(1 - t, 2) * y1 + 2 * (1 - t) * t * yi + Math.pow(t, 2) * y2 - }; - }; - - /** - * Compute the coordinates of the point positioned - * at length t in the cubic bezier curve. - * - * @param {number} t In [0,1] the step percentage to reach - * the point in the curve from the context point. - * @param {number} x1 The X coordinate of the context point. - * @param {number} y1 The Y coordinate of the context point. - * @param {number} x2 The X coordinate of the end point. - * @param {number} y2 The Y coordinate of the end point. - * @param {number} cx The X coordinate of the first control point. - * @param {number} cy The Y coordinate of the first control point. - * @param {number} dx The X coordinate of the second control point. - * @param {number} dy The Y coordinate of the second control point. - * @return {object} {x,y} The point at t. - */ - sigma.utils.getPointOnBezierCurve = - function(t, x1, y1, x2, y2, cx, cy, dx, dy) { - // http://stackoverflow.com/a/15397596 - // Blending functions: - var B0_t = Math.pow(1 - t, 3), - B1_t = 3 * t * Math.pow(1 - t, 2), - B2_t = 3 * Math.pow(t, 2) * (1 - t), - B3_t = Math.pow(t, 3); - - return { - x: (B0_t * x1) + (B1_t * cx) + (B2_t * dx) + (B3_t * x2), - y: (B0_t * y1) + (B1_t * cy) + (B2_t * dy) + (B3_t * y2) - }; - }; - - /** - * Return the coordinates of the two control points for a self loop (i.e. - * where the start point is also the end point) computed as a cubic bezier - * curve. - * - * @param {number} x The X coordinate of the node. - * @param {number} y The Y coordinate of the node. - * @param {number} size The node size. - * @return {x1,y1,x2,y2} The coordinates of the two control points. - */ - sigma.utils.getSelfLoopControlPoints = function(x , y, size) { - return { - x1: x - size * 7, - y1: y, - x2: x, - y2: y + size * 7 - }; - }; - - /** - * Return the euclidian distance between two points of a plane - * with an orthonormal basis. - * - * @param {number} x1 The X coordinate of the first point. - * @param {number} y1 The Y coordinate of the first point. - * @param {number} x2 The X coordinate of the second point. - * @param {number} y2 The Y coordinate of the second point. - * @return {number} The euclidian distance. - */ - sigma.utils.getDistance = function(x0, y0, x1, y1) { - return Math.sqrt(Math.pow(x1 - x0, 2) + Math.pow(y1 - y0, 2)); - }; - - /** - * Return the coordinates of the intersection points of two circles. - * - * @param {number} x0 The X coordinate of center location of the first - * circle. - * @param {number} y0 The Y coordinate of center location of the first - * circle. - * @param {number} r0 The radius of the first circle. - * @param {number} x1 The X coordinate of center location of the second - * circle. - * @param {number} y1 The Y coordinate of center location of the second - * circle. - * @param {number} r1 The radius of the second circle. - * @return {xi,yi} The coordinates of the intersection points. - */ - sigma.utils.getCircleIntersection = function(x0, y0, r0, x1, y1, r1) { - // http://stackoverflow.com/a/12219802 - var a, dx, dy, d, h, rx, ry, x2, y2; - - // dx and dy are the vertical and horizontal distances between the circle - // centers: - dx = x1 - x0; - dy = y1 - y0; - - // Determine the straight-line distance between the centers: - d = Math.sqrt((dy * dy) + (dx * dx)); - - // Check for solvability: - if (d > (r0 + r1)) { - // No solution. circles do not intersect. - return false; - } - if (d < Math.abs(r0 - r1)) { - // No solution. one circle is contained in the other. - return false; - } - - //'point 2' is the point where the line through the circle intersection - // points crosses the line between the circle centers. - - // Determine the distance from point 0 to point 2: - a = ((r0 * r0) - (r1 * r1) + (d * d)) / (2.0 * d); - - // Determine the coordinates of point 2: - x2 = x0 + (dx * a / d); - y2 = y0 + (dy * a / d); - - // Determine the distance from point 2 to either of the intersection - // points: - h = Math.sqrt((r0 * r0) - (a * a)); - - // Determine the offsets of the intersection points from point 2: - rx = -dy * (h / d); - ry = dx * (h / d); - - // Determine the absolute intersection points: - var xi = x2 + rx; - var xi_prime = x2 - rx; - var yi = y2 + ry; - var yi_prime = y2 - ry; - - return {xi: xi, xi_prime: xi_prime, yi: yi, yi_prime: yi_prime}; - }; - - /** - * Check if a point is on a line segment. - * - * @param {number} x The X coordinate of the point to check. - * @param {number} y The Y coordinate of the point to check. - * @param {number} x1 The X coordinate of the line start point. - * @param {number} y1 The Y coordinate of the line start point. - * @param {number} x2 The X coordinate of the line end point. - * @param {number} y2 The Y coordinate of the line end point. - * @param {number} epsilon The precision (consider the line thickness). - * @return {boolean} True if point is "close to" the line - * segment, false otherwise. - */ - sigma.utils.isPointOnSegment = function(x, y, x1, y1, x2, y2, epsilon) { - // http://stackoverflow.com/a/328122 - var crossProduct = Math.abs((y - y1) * (x2 - x1) - (x - x1) * (y2 - y1)), - d = sigma.utils.getDistance(x1, y1, x2, y2), - nCrossProduct = crossProduct / d; // normalized cross product - - return (nCrossProduct < epsilon && - Math.min(x1, x2) <= x && x <= Math.max(x1, x2) && - Math.min(y1, y2) <= y && y <= Math.max(y1, y2)); - }; - - /** - * Check if a point is on a quadratic bezier curve segment with a thickness. - * - * @param {number} x The X coordinate of the point to check. - * @param {number} y The Y coordinate of the point to check. - * @param {number} x1 The X coordinate of the curve start point. - * @param {number} y1 The Y coordinate of the curve start point. - * @param {number} x2 The X coordinate of the curve end point. - * @param {number} y2 The Y coordinate of the curve end point. - * @param {number} cpx The X coordinate of the curve control point. - * @param {number} cpy The Y coordinate of the curve control point. - * @param {number} epsilon The precision (consider the line thickness). - * @return {boolean} True if (x,y) is on the curve segment, - * false otherwise. - */ - sigma.utils.isPointOnQuadraticCurve = - function(x, y, x1, y1, x2, y2, cpx, cpy, epsilon) { - // Fails if the point is too far from the extremities of the segment, - // preventing for more costly computation: - var dP1P2 = sigma.utils.getDistance(x1, y1, x2, y2); - if (Math.abs(x - x1) > dP1P2 || Math.abs(y - y1) > dP1P2) { - return false; - } - - var dP1 = sigma.utils.getDistance(x, y, x1, y1), - dP2 = sigma.utils.getDistance(x, y, x2, y2), - t = 0.5, - r = (dP1 < dP2) ? -0.01 : 0.01, - rThreshold = 0.001, - i = 100, - pt = sigma.utils.getPointOnQuadraticCurve(t, x1, y1, x2, y2, cpx, cpy), - dt = sigma.utils.getDistance(x, y, pt.x, pt.y), - old_dt; - - // This algorithm minimizes the distance from the point to the curve. It - // find the optimal t value where t=0 is the start point and t=1 is the end - // point of the curve, starting from t=0.5. - // It terminates because it runs a maximum of i interations. - while (i-- > 0 && - t >= 0 && t <= 1 && - (dt > epsilon) && - (r > rThreshold || r < -rThreshold)) { - old_dt = dt; - pt = sigma.utils.getPointOnQuadraticCurve(t, x1, y1, x2, y2, cpx, cpy); - dt = sigma.utils.getDistance(x, y, pt.x, pt.y); - - if (dt > old_dt) { - // not the right direction: - // halfstep in the opposite direction - r = -r / 2; - t += r; - } - else if (t + r < 0 || t + r > 1) { - // oops, we've gone too far: - // revert with a halfstep - r = r / 2; - dt = old_dt; - } - else { - // progress: - t += r; - } - } - - return dt < epsilon; - }; - - - /** - * Check if a point is on a cubic bezier curve segment with a thickness. - * - * @param {number} x The X coordinate of the point to check. - * @param {number} y The Y coordinate of the point to check. - * @param {number} x1 The X coordinate of the curve start point. - * @param {number} y1 The Y coordinate of the curve start point. - * @param {number} x2 The X coordinate of the curve end point. - * @param {number} y2 The Y coordinate of the curve end point. - * @param {number} cpx1 The X coordinate of the 1st curve control point. - * @param {number} cpy1 The Y coordinate of the 1st curve control point. - * @param {number} cpx2 The X coordinate of the 2nd curve control point. - * @param {number} cpy2 The Y coordinate of the 2nd curve control point. - * @param {number} epsilon The precision (consider the line thickness). - * @return {boolean} True if (x,y) is on the curve segment, - * false otherwise. - */ - sigma.utils.isPointOnBezierCurve = - function(x, y, x1, y1, x2, y2, cpx1, cpy1, cpx2, cpy2, epsilon) { - // Fails if the point is too far from the extremities of the segment, - // preventing for more costly computation: - var dP1CP1 = sigma.utils.getDistance(x1, y1, cpx1, cpy1); - if (Math.abs(x - x1) > dP1CP1 || Math.abs(y - y1) > dP1CP1) { - return false; - } - - var dP1 = sigma.utils.getDistance(x, y, x1, y1), - dP2 = sigma.utils.getDistance(x, y, x2, y2), - t = 0.5, - r = (dP1 < dP2) ? -0.01 : 0.01, - rThreshold = 0.001, - i = 100, - pt = sigma.utils.getPointOnBezierCurve( - t, x1, y1, x2, y2, cpx1, cpy1, cpx2, cpy2), - dt = sigma.utils.getDistance(x, y, pt.x, pt.y), - old_dt; - - // This algorithm minimizes the distance from the point to the curve. It - // find the optimal t value where t=0 is the start point and t=1 is the end - // point of the curve, starting from t=0.5. - // It terminates because it runs a maximum of i interations. - while (i-- > 0 && - t >= 0 && t <= 1 && - (dt > epsilon) && - (r > rThreshold || r < -rThreshold)) { - old_dt = dt; - pt = sigma.utils.getPointOnBezierCurve( - t, x1, y1, x2, y2, cpx1, cpy1, cpx2, cpy2); - dt = sigma.utils.getDistance(x, y, pt.x, pt.y); - - if (dt > old_dt) { - // not the right direction: - // halfstep in the opposite direction - r = -r / 2; - t += r; - } - else if (t + r < 0 || t + r > 1) { - // oops, we've gone too far: - // revert with a halfstep - r = r / 2; - dt = old_dt; - } - else { - // progress: - t += r; - } - } - - return dt < epsilon; - }; - - - /** - * ************ - * EVENTS UTILS: - * ************ - */ - /** - * Here are some useful functions to unify extraction of the information we - * need with mouse events and touch events, from different browsers: - */ - - /** - * Extract the local X position from a mouse or touch event. - * - * @param {event} e A mouse or touch event. - * @return {number} The local X value of the mouse. - */ - sigma.utils.getX = function(e) { - return ( - (e.offsetX !== undefined && e.offsetX) || - (e.layerX !== undefined && e.layerX) || - (e.clientX !== undefined && e.clientX) - ); - }; - - /** - * Extract the local Y position from a mouse or touch event. - * - * @param {event} e A mouse or touch event. - * @return {number} The local Y value of the mouse. - */ - sigma.utils.getY = function(e) { - return ( - (e.offsetY !== undefined && e.offsetY) || - (e.layerY !== undefined && e.layerY) || - (e.clientY !== undefined && e.clientY) - ); - }; - - /** - * Extract the width from a mouse or touch event. - * - * @param {event} e A mouse or touch event. - * @return {number} The width of the event's target. - */ - sigma.utils.getWidth = function(e) { - var w = (!e.target.ownerSVGElement) ? - e.target.width : - e.target.ownerSVGElement.width; - - return ( - (typeof w === 'number' && w) || - (w !== undefined && w.baseVal !== undefined && w.baseVal.value) - ); - }; - - /** - * Extract the height from a mouse or touch event. - * - * @param {event} e A mouse or touch event. - * @return {number} The height of the event's target. - */ - sigma.utils.getHeight = function(e) { - var h = (!e.target.ownerSVGElement) ? - e.target.height : - e.target.ownerSVGElement.height; - - return ( - (typeof h === 'number' && h) || - (h !== undefined && h.baseVal !== undefined && h.baseVal.value) - ); - }; - - /** - * Extract the wheel delta from a mouse or touch event. - * - * @param {event} e A mouse or touch event. - * @return {number} The wheel delta of the mouse. - */ - sigma.utils.getDelta = function(e) { - return ( - (e.wheelDelta !== undefined && e.wheelDelta) || - (e.detail !== undefined && -e.detail) - ); - }; - - /** - * Returns the offset of a DOM element. - * - * @param {DOMElement} dom The element to retrieve the position. - * @return {object} The offset of the DOM element (top, left). - */ - sigma.utils.getOffset = function(dom) { - var left = 0, - top = 0; - - while (dom) { - top = top + parseInt(dom.offsetTop); - left = left + parseInt(dom.offsetLeft); - dom = dom.offsetParent; - } - - return { - top: top, - left: left - }; - }; - - /** - * Simulates a "double click" event. - * - * @param {HTMLElement} target The event target. - * @param {string} type The event type. - * @param {function} callback The callback to execute. - */ - sigma.utils.doubleClick = function(target, type, callback) { - var clicks = 0, - self = this, - handlers; - - target._doubleClickHandler = target._doubleClickHandler || {}; - target._doubleClickHandler[type] = target._doubleClickHandler[type] || []; - handlers = target._doubleClickHandler[type]; - - handlers.push(function(e) { - clicks++; - - if (clicks === 2) { - clicks = 0; - return callback(e); - } else if (clicks === 1) { - setTimeout(function() { - clicks = 0; - }, sigma.settings.doubleClickTimeout); - } - }); - - target.addEventListener(type, handlers[handlers.length - 1], false); - }; - - /** - * Unbind simulated "double click" events. - * - * @param {HTMLElement} target The event target. - * @param {string} type The event type. - */ - sigma.utils.unbindDoubleClick = function(target, type) { - var handler, - handlers = (target._doubleClickHandler || {})[type] || []; - - while ((handler = handlers.pop())) { - target.removeEventListener(type, handler); - } - - delete (target._doubleClickHandler || {})[type]; - }; - - - - - /** - * Here are just some of the most basic easing functions, used for the - * animated camera "goTo" calls. - * - * If you need some more easings functions, don't hesitate to add them to - * sigma.utils.easings. But I will not add some more here or merge PRs - * containing, because I do not want sigma sources full of overkill and never - * used stuff... - */ - sigma.utils.easings = sigma.utils.easings || {}; - sigma.utils.easings.linearNone = function(k) { - return k; - }; - sigma.utils.easings.quadraticIn = function(k) { - return k * k; - }; - sigma.utils.easings.quadraticOut = function(k) { - return k * (2 - k); - }; - sigma.utils.easings.quadraticInOut = function(k) { - if ((k *= 2) < 1) - return 0.5 * k * k; - return - 0.5 * (--k * (k - 2) - 1); - }; - sigma.utils.easings.cubicIn = function(k) { - return k * k * k; - }; - sigma.utils.easings.cubicOut = function(k) { - return --k * k * k + 1; - }; - sigma.utils.easings.cubicInOut = function(k) { - if ((k *= 2) < 1) - return 0.5 * k * k * k; - return 0.5 * ((k -= 2) * k * k + 2); - }; - - - - - /** - * ************ - * WEBGL UTILS: - * ************ - */ - /** - * Loads a WebGL shader and returns it. - * - * @param {WebGLContext} gl The WebGLContext to use. - * @param {string} shaderSource The shader source. - * @param {number} shaderType The type of shader. - * @param {function(string): void} error Callback for errors. - * @return {WebGLShader} The created shader. - */ - sigma.utils.loadShader = function(gl, shaderSource, shaderType, error) { - var compiled, - shader = gl.createShader(shaderType); - - // Load the shader source - gl.shaderSource(shader, shaderSource); - - // Compile the shader - gl.compileShader(shader); - - // Check the compile status - compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS); - - // If something went wrong: - if (!compiled) { - if (error) { - error( - 'Error compiling shader "' + shader + '":' + - gl.getShaderInfoLog(shader) - ); - } - - gl.deleteShader(shader); - return null; - } - - return shader; - }; - - /** - * Creates a program, attaches shaders, binds attrib locations, links the - * program and calls useProgram. - * - * @param {Array.<WebGLShader>} shaders The shaders to attach. - * @param {Array.<string>} attribs The attribs names. - * @param {Array.<number>} locations The locations for the attribs. - * @param {function(string): void} error Callback for errors. - * @return {WebGLProgram} The created program. - */ - sigma.utils.loadProgram = function(gl, shaders, attribs, loc, error) { - var i, - linked, - program = gl.createProgram(); - - for (i = 0; i < shaders.length; ++i) - gl.attachShader(program, shaders[i]); - - if (attribs) - for (i = 0; i < attribs.length; ++i) - gl.bindAttribLocation( - program, - locations ? locations[i] : i, - opt_attribs[i] - ); - - gl.linkProgram(program); - - // Check the link status - linked = gl.getProgramParameter(program, gl.LINK_STATUS); - if (!linked) { - if (error) - error('Error in program linking: ' + gl.getProgramInfoLog(program)); - - gl.deleteProgram(program); - return null; - } - - return program; - }; - - - - - /** - * ********* - * MATRICES: - * ********* - * The following utils are just here to help generating the transformation - * matrices for the WebGL renderers. - */ - sigma.utils.pkg('sigma.utils.matrices'); - - /** - * The returns a 3x3 translation matrix. - * - * @param {number} dx The X translation. - * @param {number} dy The Y translation. - * @return {array} Returns the matrix. - */ - sigma.utils.matrices.translation = function(dx, dy) { - return [ - 1, 0, 0, - 0, 1, 0, - dx, dy, 1 - ]; - }; - - /** - * The returns a 3x3 or 2x2 rotation matrix. - * - * @param {number} angle The rotation angle. - * @param {boolean} m2 If true, the function will return a 2x2 matrix. - * @return {array} Returns the matrix. - */ - sigma.utils.matrices.rotation = function(angle, m2) { - var cos = Math.cos(angle), - sin = Math.sin(angle); - - return m2 ? [ - cos, -sin, - sin, cos - ] : [ - cos, -sin, 0, - sin, cos, 0, - 0, 0, 1 - ]; - }; - - /** - * The returns a 3x3 or 2x2 homothetic transformation matrix. - * - * @param {number} ratio The scaling ratio. - * @param {boolean} m2 If true, the function will return a 2x2 matrix. - * @return {array} Returns the matrix. - */ - sigma.utils.matrices.scale = function(ratio, m2) { - return m2 ? [ - ratio, 0, - 0, ratio - ] : [ - ratio, 0, 0, - 0, ratio, 0, - 0, 0, 1 - ]; - }; - - /** - * The returns a 3x3 or 2x2 homothetic transformation matrix. - * - * @param {array} a The first matrix. - * @param {array} b The second matrix. - * @param {boolean} m2 If true, the function will assume both matrices are - * 2x2. - * @return {array} Returns the matrix. - */ - sigma.utils.matrices.multiply = function(a, b, m2) { - var l = m2 ? 2 : 3, - a00 = a[0 * l + 0], - a01 = a[0 * l + 1], - a02 = a[0 * l + 2], - a10 = a[1 * l + 0], - a11 = a[1 * l + 1], - a12 = a[1 * l + 2], - a20 = a[2 * l + 0], - a21 = a[2 * l + 1], - a22 = a[2 * l + 2], - b00 = b[0 * l + 0], - b01 = b[0 * l + 1], - b02 = b[0 * l + 2], - b10 = b[1 * l + 0], - b11 = b[1 * l + 1], - b12 = b[1 * l + 2], - b20 = b[2 * l + 0], - b21 = b[2 * l + 1], - b22 = b[2 * l + 2]; - - return m2 ? [ - a00 * b00 + a01 * b10, - a00 * b01 + a01 * b11, - a10 * b00 + a11 * b10, - a10 * b01 + a11 * b11 - ] : [ - a00 * b00 + a01 * b10 + a02 * b20, - a00 * b01 + a01 * b11 + a02 * b21, - a00 * b02 + a01 * b12 + a02 * b22, - a10 * b00 + a11 * b10 + a12 * b20, - a10 * b01 + a11 * b11 + a12 * b21, - a10 * b02 + a11 * b12 + a12 * b22, - a20 * b00 + a21 * b10 + a22 * b20, - a20 * b01 + a21 * b11 + a22 * b21, - a20 * b02 + a21 * b12 + a22 * b22 - ]; - }; -}).call(this); diff --git a/src/demo/util.py b/src/demo/util.py deleted file mode 100644 index b835d33b4..000000000 --- a/src/demo/util.py +++ /dev/null @@ -1,58 +0,0 @@ -# -*- coding: utf-8 -*- - -''' -python utilities -''' - -import os -import sys -import json - - -def get_env(env_name, default=None, type=None): - ''' - Fetches environment variable. - ''' - if env_name in os.environ and type: - return type(os.environ[env_name]) - elif env_name in os.environ: - return os.environ[env_name] - elif type: - return type(default) - - return default - - -def set_modul_attrs(name, values): - """ - Updates the module with the values. - - :param name: str, module name, if this method call is located - inside module then use __name__ - :param values: dict, contains new key values. - """ - # get the config module (this module) - config_module = sys.modules[name] - - # set all the values for given keys on this module - for key, value in values.items(): - setattr(config_module, key, value) - - -def load_module_attrs(name, env_flag): - """ - A function for initializing module from config files (JSON formatted). - Called when loading the module. The module is specified by it's name. - - :param name: str, module name, if this method call is located - inside module then use __name__ - :param env_flag: str, name of the env variable in which is path to JSON - file from which module attributes are going to be - populated - :param argv_flag: str, name of program argument which will define path - to the json file - """ - config_path = get_env(env_flag) - if config_path: - with open(config_path, 'r') as config_file: - set_modul_attrs(name, json.load(config_file)) diff --git a/src/demo/web_service.py b/src/demo/web_service.py deleted file mode 100644 index 553a352d2..000000000 --- a/src/demo/web_service.py +++ /dev/null @@ -1,34 +0,0 @@ -# -*- coding: utf-8 -*- - -from flask import Flask - - -class WebService(object): - - def __init__(self, name): - ''' - ''' - self.server = Flask(__name__) - - def add_route(self, route, code_method, http_method): - ''' - Registers URL rule - - :param route: str, route string - :param object_method: object method responsible for the - request handling - :param http_method: name of http method - ''' - self.server.add_url_rule(route, '%s_%s' % (route, http_method), - code_method, methods=[http_method]) - - def setup_routes(self): - ''' - ''' - self.add_route('/ping', self.ping, 'GET') - - def ping(self): - ''' - Ping endpoint. Returns 204 HTTP status code. - ''' - return ('', 204) diff --git a/src/demo/worker/.gitignore b/src/demo/worker/.gitignore deleted file mode 100644 index 0df30e2b7..000000000 --- a/src/demo/worker/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -*.so -build/ -__*__.cpp diff --git a/src/demo/worker/__init__.py b/src/demo/worker/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/demo/worker/benchmark.cpp b/src/demo/worker/benchmark.cpp deleted file mode 100644 index 791084afb..000000000 --- a/src/demo/worker/benchmark.cpp +++ /dev/null @@ -1,2393 +0,0 @@ -/* Generated by Cython 0.23.4 */ - -#define PY_SSIZE_T_CLEAN -#include "Python.h" -#ifndef Py_PYTHON_H - #error Python headers needed to compile C extensions, please install development version of Python. -#elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03020000) - #error Cython requires Python 2.6+ or Python 3.2+. -#else -#define CYTHON_ABI "0_23_4" -#include <stddef.h> -#ifndef offsetof -#define offsetof(type, member) ( (size_t) & ((type*)0) -> member ) -#endif -#if !defined(WIN32) && !defined(MS_WINDOWS) - #ifndef __stdcall - #define __stdcall - #endif - #ifndef __cdecl - #define __cdecl - #endif - #ifndef __fastcall - #define __fastcall - #endif -#endif -#ifndef DL_IMPORT - #define DL_IMPORT(t) t -#endif -#ifndef DL_EXPORT - #define DL_EXPORT(t) t -#endif -#ifndef PY_LONG_LONG - #define PY_LONG_LONG LONG_LONG -#endif -#ifndef Py_HUGE_VAL - #define Py_HUGE_VAL HUGE_VAL -#endif -#ifdef PYPY_VERSION -#define CYTHON_COMPILING_IN_PYPY 1 -#define CYTHON_COMPILING_IN_CPYTHON 0 -#else -#define CYTHON_COMPILING_IN_PYPY 0 -#define CYTHON_COMPILING_IN_CPYTHON 1 -#endif -#if !defined(CYTHON_USE_PYLONG_INTERNALS) && CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x02070000 -#define CYTHON_USE_PYLONG_INTERNALS 1 -#endif -#if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX < 0x02070600 && !defined(Py_OptimizeFlag) -#define Py_OptimizeFlag 0 -#endif -#define __PYX_BUILD_PY_SSIZE_T "n" -#define CYTHON_FORMAT_SSIZE_T "z" -#if PY_MAJOR_VERSION < 3 - #define __Pyx_BUILTIN_MODULE_NAME "__builtin__" - #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ - PyCode_New(a+k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) - #define __Pyx_DefaultClassType PyClass_Type -#else - #define __Pyx_BUILTIN_MODULE_NAME "builtins" - #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ - PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) - #define __Pyx_DefaultClassType PyType_Type -#endif -#ifndef Py_TPFLAGS_CHECKTYPES - #define Py_TPFLAGS_CHECKTYPES 0 -#endif -#ifndef Py_TPFLAGS_HAVE_INDEX - #define Py_TPFLAGS_HAVE_INDEX 0 -#endif -#ifndef Py_TPFLAGS_HAVE_NEWBUFFER - #define Py_TPFLAGS_HAVE_NEWBUFFER 0 -#endif -#ifndef Py_TPFLAGS_HAVE_FINALIZE - #define Py_TPFLAGS_HAVE_FINALIZE 0 -#endif -#if PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND) - #define CYTHON_PEP393_ENABLED 1 - #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ?\ - 0 : _PyUnicode_Ready((PyObject *)(op))) - #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_LENGTH(u) - #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i) - #define __Pyx_PyUnicode_KIND(u) PyUnicode_KIND(u) - #define __Pyx_PyUnicode_DATA(u) PyUnicode_DATA(u) - #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i) -#else - #define CYTHON_PEP393_ENABLED 0 - #define __Pyx_PyUnicode_READY(op) (0) - #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_SIZE(u) - #define __Pyx_PyUnicode_READ_CHAR(u, i) ((Py_UCS4)(PyUnicode_AS_UNICODE(u)[i])) - #define __Pyx_PyUnicode_KIND(u) (sizeof(Py_UNICODE)) - #define __Pyx_PyUnicode_DATA(u) ((void*)PyUnicode_AS_UNICODE(u)) - #define __Pyx_PyUnicode_READ(k, d, i) ((void)(k), (Py_UCS4)(((Py_UNICODE*)d)[i])) -#endif -#if CYTHON_COMPILING_IN_PYPY - #define __Pyx_PyUnicode_Concat(a, b) PyNumber_Add(a, b) - #define __Pyx_PyUnicode_ConcatSafe(a, b) PyNumber_Add(a, b) -#else - #define __Pyx_PyUnicode_Concat(a, b) PyUnicode_Concat(a, b) - #define __Pyx_PyUnicode_ConcatSafe(a, b) ((unlikely((a) == Py_None) || unlikely((b) == Py_None)) ?\ - PyNumber_Add(a, b) : __Pyx_PyUnicode_Concat(a, b)) -#endif -#if CYTHON_COMPILING_IN_PYPY && !defined(PyUnicode_Contains) - #define PyUnicode_Contains(u, s) PySequence_Contains(u, s) -#endif -#define __Pyx_PyString_FormatSafe(a, b) ((unlikely((a) == Py_None)) ? PyNumber_Remainder(a, b) : __Pyx_PyString_Format(a, b)) -#define __Pyx_PyUnicode_FormatSafe(a, b) ((unlikely((a) == Py_None)) ? PyNumber_Remainder(a, b) : PyUnicode_Format(a, b)) -#if PY_MAJOR_VERSION >= 3 - #define __Pyx_PyString_Format(a, b) PyUnicode_Format(a, b) -#else - #define __Pyx_PyString_Format(a, b) PyString_Format(a, b) -#endif -#if PY_MAJOR_VERSION >= 3 - #define PyBaseString_Type PyUnicode_Type - #define PyStringObject PyUnicodeObject - #define PyString_Type PyUnicode_Type - #define PyString_Check PyUnicode_Check - #define PyString_CheckExact PyUnicode_CheckExact -#endif -#if PY_MAJOR_VERSION >= 3 - #define __Pyx_PyBaseString_Check(obj) PyUnicode_Check(obj) - #define __Pyx_PyBaseString_CheckExact(obj) PyUnicode_CheckExact(obj) -#else - #define __Pyx_PyBaseString_Check(obj) (PyString_Check(obj) || PyUnicode_Check(obj)) - #define __Pyx_PyBaseString_CheckExact(obj) (PyString_CheckExact(obj) || PyUnicode_CheckExact(obj)) -#endif -#ifndef PySet_CheckExact - #define PySet_CheckExact(obj) (Py_TYPE(obj) == &PySet_Type) -#endif -#define __Pyx_TypeCheck(obj, type) PyObject_TypeCheck(obj, (PyTypeObject *)type) -#if PY_MAJOR_VERSION >= 3 - #define PyIntObject PyLongObject - #define PyInt_Type PyLong_Type - #define PyInt_Check(op) PyLong_Check(op) - #define PyInt_CheckExact(op) PyLong_CheckExact(op) - #define PyInt_FromString PyLong_FromString - #define PyInt_FromUnicode PyLong_FromUnicode - #define PyInt_FromLong PyLong_FromLong - #define PyInt_FromSize_t PyLong_FromSize_t - #define PyInt_FromSsize_t PyLong_FromSsize_t - #define PyInt_AsLong PyLong_AsLong - #define PyInt_AS_LONG PyLong_AS_LONG - #define PyInt_AsSsize_t PyLong_AsSsize_t - #define PyInt_AsUnsignedLongMask PyLong_AsUnsignedLongMask - #define PyInt_AsUnsignedLongLongMask PyLong_AsUnsignedLongLongMask - #define PyNumber_Int PyNumber_Long -#endif -#if PY_MAJOR_VERSION >= 3 - #define PyBoolObject PyLongObject -#endif -#if PY_MAJOR_VERSION >= 3 && CYTHON_COMPILING_IN_PYPY - #ifndef PyUnicode_InternFromString - #define PyUnicode_InternFromString(s) PyUnicode_FromString(s) - #endif -#endif -#if PY_VERSION_HEX < 0x030200A4 - typedef long Py_hash_t; - #define __Pyx_PyInt_FromHash_t PyInt_FromLong - #define __Pyx_PyInt_AsHash_t PyInt_AsLong -#else - #define __Pyx_PyInt_FromHash_t PyInt_FromSsize_t - #define __Pyx_PyInt_AsHash_t PyInt_AsSsize_t -#endif -#if PY_MAJOR_VERSION >= 3 - #define __Pyx_PyMethod_New(func, self, klass) ((self) ? PyMethod_New(func, self) : PyInstanceMethod_New(func)) -#else - #define __Pyx_PyMethod_New(func, self, klass) PyMethod_New(func, self, klass) -#endif -#if PY_VERSION_HEX >= 0x030500B1 -#define __Pyx_PyAsyncMethodsStruct PyAsyncMethods -#define __Pyx_PyType_AsAsync(obj) (Py_TYPE(obj)->tp_as_async) -#elif CYTHON_COMPILING_IN_CPYTHON && PY_MAJOR_VERSION >= 3 -typedef struct { - unaryfunc am_await; - unaryfunc am_aiter; - unaryfunc am_anext; -} __Pyx_PyAsyncMethodsStruct; -#define __Pyx_PyType_AsAsync(obj) ((__Pyx_PyAsyncMethodsStruct*) (Py_TYPE(obj)->tp_reserved)) -#else -#define __Pyx_PyType_AsAsync(obj) NULL -#endif -#ifndef CYTHON_RESTRICT - #if defined(__GNUC__) - #define CYTHON_RESTRICT __restrict__ - #elif defined(_MSC_VER) && _MSC_VER >= 1400 - #define CYTHON_RESTRICT __restrict - #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L - #define CYTHON_RESTRICT restrict - #else - #define CYTHON_RESTRICT - #endif -#endif -#define __Pyx_void_to_None(void_result) ((void)(void_result), Py_INCREF(Py_None), Py_None) - -#ifndef __cplusplus - #error "Cython files generated with the C++ option must be compiled with a C++ compiler." -#endif -#ifndef CYTHON_INLINE - #define CYTHON_INLINE inline -#endif -template<typename T> -void __Pyx_call_destructor(T& x) { - x.~T(); -} -template<typename T> -class __Pyx_FakeReference { - public: - __Pyx_FakeReference() : ptr(NULL) { } - __Pyx_FakeReference(const T& ref) : ptr(const_cast<T*>(&ref)) { } - T *operator->() { return ptr; } - operator T&() { return *ptr; } - private: - T *ptr; -}; - -#if defined(WIN32) || defined(MS_WINDOWS) - #define _USE_MATH_DEFINES -#endif -#include <math.h> -#ifdef NAN -#define __PYX_NAN() ((float) NAN) -#else -static CYTHON_INLINE float __PYX_NAN() { - float value; - memset(&value, 0xFF, sizeof(value)); - return value; -} -#endif - - -#if PY_MAJOR_VERSION >= 3 - #define __Pyx_PyNumber_Divide(x,y) PyNumber_TrueDivide(x,y) - #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceTrueDivide(x,y) -#else - #define __Pyx_PyNumber_Divide(x,y) PyNumber_Divide(x,y) - #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceDivide(x,y) -#endif - -#ifndef __PYX_EXTERN_C - #ifdef __cplusplus - #define __PYX_EXTERN_C extern "C" - #else - #define __PYX_EXTERN_C extern - #endif -#endif - -#define __PYX_HAVE__benchmark -#define __PYX_HAVE_API__benchmark -#include "string.h" -#include <string> -#include "ios" -#include "new" -#include "stdexcept" -#include "typeinfo" -#include <vector> -#include "benchmark.hpp" -#ifdef _OPENMP -#include <omp.h> -#endif /* _OPENMP */ - -#ifdef PYREX_WITHOUT_ASSERTIONS -#define CYTHON_WITHOUT_ASSERTIONS -#endif - -#ifndef CYTHON_UNUSED -# if defined(__GNUC__) -# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) -# define CYTHON_UNUSED __attribute__ ((__unused__)) -# else -# define CYTHON_UNUSED -# endif -# elif defined(__ICC) || (defined(__INTEL_COMPILER) && !defined(_MSC_VER)) -# define CYTHON_UNUSED __attribute__ ((__unused__)) -# else -# define CYTHON_UNUSED -# endif -#endif -#ifndef CYTHON_NCP_UNUSED -# if CYTHON_COMPILING_IN_CPYTHON -# define CYTHON_NCP_UNUSED -# else -# define CYTHON_NCP_UNUSED CYTHON_UNUSED -# endif -#endif -typedef struct {PyObject **p; char *s; const Py_ssize_t n; const char* encoding; - const char is_unicode; const char is_str; const char intern; } __Pyx_StringTabEntry; - -#define __PYX_DEFAULT_STRING_ENCODING_IS_ASCII 0 -#define __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT 0 -#define __PYX_DEFAULT_STRING_ENCODING "" -#define __Pyx_PyObject_FromString __Pyx_PyBytes_FromString -#define __Pyx_PyObject_FromStringAndSize __Pyx_PyBytes_FromStringAndSize -#define __Pyx_uchar_cast(c) ((unsigned char)c) -#define __Pyx_long_cast(x) ((long)x) -#define __Pyx_fits_Py_ssize_t(v, type, is_signed) (\ - (sizeof(type) < sizeof(Py_ssize_t)) ||\ - (sizeof(type) > sizeof(Py_ssize_t) &&\ - likely(v < (type)PY_SSIZE_T_MAX ||\ - v == (type)PY_SSIZE_T_MAX) &&\ - (!is_signed || likely(v > (type)PY_SSIZE_T_MIN ||\ - v == (type)PY_SSIZE_T_MIN))) ||\ - (sizeof(type) == sizeof(Py_ssize_t) &&\ - (is_signed || likely(v < (type)PY_SSIZE_T_MAX ||\ - v == (type)PY_SSIZE_T_MAX))) ) -#if defined (__cplusplus) && __cplusplus >= 201103L - #include <cstdlib> - #define __Pyx_sst_abs(value) std::abs(value) -#elif SIZEOF_INT >= SIZEOF_SIZE_T - #define __Pyx_sst_abs(value) abs(value) -#elif SIZEOF_LONG >= SIZEOF_SIZE_T - #define __Pyx_sst_abs(value) labs(value) -#elif defined (_MSC_VER) && defined (_M_X64) - #define __Pyx_sst_abs(value) _abs64(value) -#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L - #define __Pyx_sst_abs(value) llabs(value) -#elif defined (__GNUC__) - #define __Pyx_sst_abs(value) __builtin_llabs(value) -#else - #define __Pyx_sst_abs(value) ((value<0) ? -value : value) -#endif -static CYTHON_INLINE char* __Pyx_PyObject_AsString(PyObject*); -static CYTHON_INLINE char* __Pyx_PyObject_AsStringAndSize(PyObject*, Py_ssize_t* length); -#define __Pyx_PyByteArray_FromString(s) PyByteArray_FromStringAndSize((const char*)s, strlen((const char*)s)) -#define __Pyx_PyByteArray_FromStringAndSize(s, l) PyByteArray_FromStringAndSize((const char*)s, l) -#define __Pyx_PyBytes_FromString PyBytes_FromString -#define __Pyx_PyBytes_FromStringAndSize PyBytes_FromStringAndSize -static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char*); -#if PY_MAJOR_VERSION < 3 - #define __Pyx_PyStr_FromString __Pyx_PyBytes_FromString - #define __Pyx_PyStr_FromStringAndSize __Pyx_PyBytes_FromStringAndSize -#else - #define __Pyx_PyStr_FromString __Pyx_PyUnicode_FromString - #define __Pyx_PyStr_FromStringAndSize __Pyx_PyUnicode_FromStringAndSize -#endif -#define __Pyx_PyObject_AsSString(s) ((signed char*) __Pyx_PyObject_AsString(s)) -#define __Pyx_PyObject_AsUString(s) ((unsigned char*) __Pyx_PyObject_AsString(s)) -#define __Pyx_PyObject_FromCString(s) __Pyx_PyObject_FromString((const char*)s) -#define __Pyx_PyBytes_FromCString(s) __Pyx_PyBytes_FromString((const char*)s) -#define __Pyx_PyByteArray_FromCString(s) __Pyx_PyByteArray_FromString((const char*)s) -#define __Pyx_PyStr_FromCString(s) __Pyx_PyStr_FromString((const char*)s) -#define __Pyx_PyUnicode_FromCString(s) __Pyx_PyUnicode_FromString((const char*)s) -#if PY_MAJOR_VERSION < 3 -static CYTHON_INLINE size_t __Pyx_Py_UNICODE_strlen(const Py_UNICODE *u) -{ - const Py_UNICODE *u_end = u; - while (*u_end++) ; - return (size_t)(u_end - u - 1); -} -#else -#define __Pyx_Py_UNICODE_strlen Py_UNICODE_strlen -#endif -#define __Pyx_PyUnicode_FromUnicode(u) PyUnicode_FromUnicode(u, __Pyx_Py_UNICODE_strlen(u)) -#define __Pyx_PyUnicode_FromUnicodeAndLength PyUnicode_FromUnicode -#define __Pyx_PyUnicode_AsUnicode PyUnicode_AsUnicode -#define __Pyx_NewRef(obj) (Py_INCREF(obj), obj) -#define __Pyx_Owned_Py_None(b) __Pyx_NewRef(Py_None) -#define __Pyx_PyBool_FromLong(b) ((b) ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False)) -static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*); -static CYTHON_INLINE PyObject* __Pyx_PyNumber_Int(PyObject* x); -static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); -static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); -#if CYTHON_COMPILING_IN_CPYTHON -#define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) -#else -#define __pyx_PyFloat_AsDouble(x) PyFloat_AsDouble(x) -#endif -#define __pyx_PyFloat_AsFloat(x) ((float) __pyx_PyFloat_AsDouble(x)) -#if PY_MAJOR_VERSION < 3 && __PYX_DEFAULT_STRING_ENCODING_IS_ASCII -static int __Pyx_sys_getdefaultencoding_not_ascii; -static int __Pyx_init_sys_getdefaultencoding_params(void) { - PyObject* sys; - PyObject* default_encoding = NULL; - PyObject* ascii_chars_u = NULL; - PyObject* ascii_chars_b = NULL; - const char* default_encoding_c; - sys = PyImport_ImportModule("sys"); - if (!sys) goto bad; - default_encoding = PyObject_CallMethod(sys, (char*) "getdefaultencoding", NULL); - Py_DECREF(sys); - if (!default_encoding) goto bad; - default_encoding_c = PyBytes_AsString(default_encoding); - if (!default_encoding_c) goto bad; - if (strcmp(default_encoding_c, "ascii") == 0) { - __Pyx_sys_getdefaultencoding_not_ascii = 0; - } else { - char ascii_chars[128]; - int c; - for (c = 0; c < 128; c++) { - ascii_chars[c] = c; - } - __Pyx_sys_getdefaultencoding_not_ascii = 1; - ascii_chars_u = PyUnicode_DecodeASCII(ascii_chars, 128, NULL); - if (!ascii_chars_u) goto bad; - ascii_chars_b = PyUnicode_AsEncodedString(ascii_chars_u, default_encoding_c, NULL); - if (!ascii_chars_b || !PyBytes_Check(ascii_chars_b) || memcmp(ascii_chars, PyBytes_AS_STRING(ascii_chars_b), 128) != 0) { - PyErr_Format( - PyExc_ValueError, - "This module compiled with c_string_encoding=ascii, but default encoding '%.200s' is not a superset of ascii.", - default_encoding_c); - goto bad; - } - Py_DECREF(ascii_chars_u); - Py_DECREF(ascii_chars_b); - } - Py_DECREF(default_encoding); - return 0; -bad: - Py_XDECREF(default_encoding); - Py_XDECREF(ascii_chars_u); - Py_XDECREF(ascii_chars_b); - return -1; -} -#endif -#if __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT && PY_MAJOR_VERSION >= 3 -#define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_DecodeUTF8(c_str, size, NULL) -#else -#define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_Decode(c_str, size, __PYX_DEFAULT_STRING_ENCODING, NULL) -#if __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT -static char* __PYX_DEFAULT_STRING_ENCODING; -static int __Pyx_init_sys_getdefaultencoding_params(void) { - PyObject* sys; - PyObject* default_encoding = NULL; - char* default_encoding_c; - sys = PyImport_ImportModule("sys"); - if (!sys) goto bad; - default_encoding = PyObject_CallMethod(sys, (char*) (const char*) "getdefaultencoding", NULL); - Py_DECREF(sys); - if (!default_encoding) goto bad; - default_encoding_c = PyBytes_AsString(default_encoding); - if (!default_encoding_c) goto bad; - __PYX_DEFAULT_STRING_ENCODING = (char*) malloc(strlen(default_encoding_c)); - if (!__PYX_DEFAULT_STRING_ENCODING) goto bad; - strcpy(__PYX_DEFAULT_STRING_ENCODING, default_encoding_c); - Py_DECREF(default_encoding); - return 0; -bad: - Py_XDECREF(default_encoding); - return -1; -} -#endif -#endif - - -/* Test for GCC > 2.95 */ -#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95))) - #define likely(x) __builtin_expect(!!(x), 1) - #define unlikely(x) __builtin_expect(!!(x), 0) -#else /* !__GNUC__ or GCC < 2.95 */ - #define likely(x) (x) - #define unlikely(x) (x) -#endif /* __GNUC__ */ - -static PyObject *__pyx_m; -static PyObject *__pyx_d; -static PyObject *__pyx_b; -static PyObject *__pyx_empty_tuple; -static PyObject *__pyx_empty_bytes; -static int __pyx_lineno; -static int __pyx_clineno = 0; -static const char * __pyx_cfilenm= __FILE__; -static const char *__pyx_filename; - - -static const char *__pyx_f[] = { - "benchmark.pyx", - "stringsource", -}; - -/*--- Type declarations ---*/ - -/* --- Runtime support code (head) --- */ -#ifndef CYTHON_REFNANNY - #define CYTHON_REFNANNY 0 -#endif -#if CYTHON_REFNANNY - typedef struct { - void (*INCREF)(void*, PyObject*, int); - void (*DECREF)(void*, PyObject*, int); - void (*GOTREF)(void*, PyObject*, int); - void (*GIVEREF)(void*, PyObject*, int); - void* (*SetupContext)(const char*, int, const char*); - void (*FinishContext)(void**); - } __Pyx_RefNannyAPIStruct; - static __Pyx_RefNannyAPIStruct *__Pyx_RefNanny = NULL; - static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname); - #define __Pyx_RefNannyDeclarations void *__pyx_refnanny = NULL; -#ifdef WITH_THREAD - #define __Pyx_RefNannySetupContext(name, acquire_gil)\ - if (acquire_gil) {\ - PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ - __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__);\ - PyGILState_Release(__pyx_gilstate_save);\ - } else {\ - __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__);\ - } -#else - #define __Pyx_RefNannySetupContext(name, acquire_gil)\ - __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__) -#endif - #define __Pyx_RefNannyFinishContext()\ - __Pyx_RefNanny->FinishContext(&__pyx_refnanny) - #define __Pyx_INCREF(r) __Pyx_RefNanny->INCREF(__pyx_refnanny, (PyObject *)(r), __LINE__) - #define __Pyx_DECREF(r) __Pyx_RefNanny->DECREF(__pyx_refnanny, (PyObject *)(r), __LINE__) - #define __Pyx_GOTREF(r) __Pyx_RefNanny->GOTREF(__pyx_refnanny, (PyObject *)(r), __LINE__) - #define __Pyx_GIVEREF(r) __Pyx_RefNanny->GIVEREF(__pyx_refnanny, (PyObject *)(r), __LINE__) - #define __Pyx_XINCREF(r) do { if((r) != NULL) {__Pyx_INCREF(r); }} while(0) - #define __Pyx_XDECREF(r) do { if((r) != NULL) {__Pyx_DECREF(r); }} while(0) - #define __Pyx_XGOTREF(r) do { if((r) != NULL) {__Pyx_GOTREF(r); }} while(0) - #define __Pyx_XGIVEREF(r) do { if((r) != NULL) {__Pyx_GIVEREF(r);}} while(0) -#else - #define __Pyx_RefNannyDeclarations - #define __Pyx_RefNannySetupContext(name, acquire_gil) - #define __Pyx_RefNannyFinishContext() - #define __Pyx_INCREF(r) Py_INCREF(r) - #define __Pyx_DECREF(r) Py_DECREF(r) - #define __Pyx_GOTREF(r) - #define __Pyx_GIVEREF(r) - #define __Pyx_XINCREF(r) Py_XINCREF(r) - #define __Pyx_XDECREF(r) Py_XDECREF(r) - #define __Pyx_XGOTREF(r) - #define __Pyx_XGIVEREF(r) -#endif -#define __Pyx_XDECREF_SET(r, v) do {\ - PyObject *tmp = (PyObject *) r;\ - r = v; __Pyx_XDECREF(tmp);\ - } while (0) -#define __Pyx_DECREF_SET(r, v) do {\ - PyObject *tmp = (PyObject *) r;\ - r = v; __Pyx_DECREF(tmp);\ - } while (0) -#define __Pyx_CLEAR(r) do { PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);} while(0) -#define __Pyx_XCLEAR(r) do { if((r) != NULL) {PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);}} while(0) - -static void __Pyx_RaiseArgtupleInvalid(const char* func_name, int exact, - Py_ssize_t num_min, Py_ssize_t num_max, Py_ssize_t num_found); - -static void __Pyx_RaiseDoubleKeywordsError(const char* func_name, PyObject* kw_name); - -static int __Pyx_ParseOptionalKeywords(PyObject *kwds, PyObject **argnames[],\ - PyObject *kwds2, PyObject *values[], Py_ssize_t num_pos_args,\ - const char* function_name); - -typedef struct { - int code_line; - PyCodeObject* code_object; -} __Pyx_CodeObjectCacheEntry; -struct __Pyx_CodeObjectCache { - int count; - int max_count; - __Pyx_CodeObjectCacheEntry* entries; -}; -static struct __Pyx_CodeObjectCache __pyx_code_cache = {0,0,NULL}; -static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line); -static PyCodeObject *__pyx_find_code_object(int code_line); -static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object); - -static void __Pyx_AddTraceback(const char *funcname, int c_line, - int py_line, const char *filename); - -static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); - -static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); - -static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *); - -static int __Pyx_check_binary_version(void); - -static int __Pyx_InitStrings(__Pyx_StringTabEntry *t); - - -/* Module declarations from 'libc.string' */ - -/* Module declarations from 'libcpp.string' */ - -/* Module declarations from 'libcpp.vector' */ - -/* Module declarations from 'benchmark' */ -static std::string __pyx_convert_string_from_py_std__in_string(PyObject *); /*proto*/ -static std::vector<std::string> __pyx_convert_vector_from_py_std_3a__3a_string(PyObject *); /*proto*/ -static CYTHON_INLINE PyObject *__pyx_convert_PyObject_string_to_py_std__in_string(std::string const &); /*proto*/ -static CYTHON_INLINE PyObject *__pyx_convert_PyUnicode_string_to_py_std__in_string(std::string const &); /*proto*/ -static CYTHON_INLINE PyObject *__pyx_convert_PyStr_string_to_py_std__in_string(std::string const &); /*proto*/ -static CYTHON_INLINE PyObject *__pyx_convert_PyBytes_string_to_py_std__in_string(std::string const &); /*proto*/ -static CYTHON_INLINE PyObject *__pyx_convert_PyByteArray_string_to_py_std__in_string(std::string const &); /*proto*/ -#define __Pyx_MODULE_NAME "benchmark" -int __pyx_module_is_main_benchmark = 0; - -/* Implementation of 'benchmark' */ -static char __pyx_k_host[] = "host"; -static char __pyx_k_main[] = "__main__"; -static char __pyx_k_port[] = "port"; -static char __pyx_k_test[] = "__test__"; -static char __pyx_k_result[] = "result"; -static char __pyx_k_queries[] = "queries"; -static char __pyx_k_duration[] = "duration"; -static char __pyx_k_benchmark[] = "benchmark"; -static char __pyx_k_connections_per_query[] = "connections_per_query"; -static char __pyx_k_home_buda_Local_memgraph_demo_w[] = "/home/buda/Local/memgraph/demo/worker/benchmark.pyx"; -static PyObject *__pyx_n_s_benchmark; -static PyObject *__pyx_n_s_connections_per_query; -static PyObject *__pyx_n_s_duration; -static PyObject *__pyx_kp_s_home_buda_Local_memgraph_demo_w; -static PyObject *__pyx_n_s_host; -static PyObject *__pyx_n_s_main; -static PyObject *__pyx_n_s_port; -static PyObject *__pyx_n_s_queries; -static PyObject *__pyx_n_s_result; -static PyObject *__pyx_n_s_test; -static PyObject *__pyx_pf_9benchmark_benchmark(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_host, PyObject *__pyx_v_port, PyObject *__pyx_v_connections_per_query, PyObject *__pyx_v_duration, PyObject *__pyx_v_queries); /* proto */ -static PyObject *__pyx_tuple_; -static PyObject *__pyx_codeobj__2; - -/* "benchmark.pyx":14 - * - * - * def benchmark(host, port, connections_per_query, duration, queries): # <<<<<<<<<<<<<< - * ''' - * ''' - */ - -/* Python wrapper */ -static PyObject *__pyx_pw_9benchmark_1benchmark(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static char __pyx_doc_9benchmark_benchmark[] = "\n "; -static PyMethodDef __pyx_mdef_9benchmark_1benchmark = {"benchmark", (PyCFunction)__pyx_pw_9benchmark_1benchmark, METH_VARARGS|METH_KEYWORDS, __pyx_doc_9benchmark_benchmark}; -static PyObject *__pyx_pw_9benchmark_1benchmark(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyObject *__pyx_v_host = 0; - PyObject *__pyx_v_port = 0; - PyObject *__pyx_v_connections_per_query = 0; - PyObject *__pyx_v_duration = 0; - PyObject *__pyx_v_queries = 0; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("benchmark (wrapper)", 0); - { - static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_host,&__pyx_n_s_port,&__pyx_n_s_connections_per_query,&__pyx_n_s_duration,&__pyx_n_s_queries,0}; - PyObject* values[5] = {0,0,0,0,0}; - if (unlikely(__pyx_kwds)) { - Py_ssize_t kw_args; - const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); - switch (pos_args) { - case 5: values[4] = PyTuple_GET_ITEM(__pyx_args, 4); - case 4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3); - case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); - case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); - case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); - case 0: break; - default: goto __pyx_L5_argtuple_error; - } - kw_args = PyDict_Size(__pyx_kwds); - switch (pos_args) { - case 0: - if (likely((values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_host)) != 0)) kw_args--; - else goto __pyx_L5_argtuple_error; - case 1: - if (likely((values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_port)) != 0)) kw_args--; - else { - __Pyx_RaiseArgtupleInvalid("benchmark", 1, 5, 5, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 14; __pyx_clineno = __LINE__; goto __pyx_L3_error;} - } - case 2: - if (likely((values[2] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_connections_per_query)) != 0)) kw_args--; - else { - __Pyx_RaiseArgtupleInvalid("benchmark", 1, 5, 5, 2); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 14; __pyx_clineno = __LINE__; goto __pyx_L3_error;} - } - case 3: - if (likely((values[3] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_duration)) != 0)) kw_args--; - else { - __Pyx_RaiseArgtupleInvalid("benchmark", 1, 5, 5, 3); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 14; __pyx_clineno = __LINE__; goto __pyx_L3_error;} - } - case 4: - if (likely((values[4] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_queries)) != 0)) kw_args--; - else { - __Pyx_RaiseArgtupleInvalid("benchmark", 1, 5, 5, 4); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 14; __pyx_clineno = __LINE__; goto __pyx_L3_error;} - } - } - if (unlikely(kw_args > 0)) { - if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "benchmark") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 14; __pyx_clineno = __LINE__; goto __pyx_L3_error;} - } - } else if (PyTuple_GET_SIZE(__pyx_args) != 5) { - goto __pyx_L5_argtuple_error; - } else { - values[0] = PyTuple_GET_ITEM(__pyx_args, 0); - values[1] = PyTuple_GET_ITEM(__pyx_args, 1); - values[2] = PyTuple_GET_ITEM(__pyx_args, 2); - values[3] = PyTuple_GET_ITEM(__pyx_args, 3); - values[4] = PyTuple_GET_ITEM(__pyx_args, 4); - } - __pyx_v_host = values[0]; - __pyx_v_port = values[1]; - __pyx_v_connections_per_query = values[2]; - __pyx_v_duration = values[3]; - __pyx_v_queries = values[4]; - } - goto __pyx_L4_argument_unpacking_done; - __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("benchmark", 1, 5, 5, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 14; __pyx_clineno = __LINE__; goto __pyx_L3_error;} - __pyx_L3_error:; - __Pyx_AddTraceback("benchmark.benchmark", __pyx_clineno, __pyx_lineno, __pyx_filename); - __Pyx_RefNannyFinishContext(); - return NULL; - __pyx_L4_argument_unpacking_done:; - __pyx_r = __pyx_pf_9benchmark_benchmark(__pyx_self, __pyx_v_host, __pyx_v_port, __pyx_v_connections_per_query, __pyx_v_duration, __pyx_v_queries); - - /* function exit code */ - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -static PyObject *__pyx_pf_9benchmark_benchmark(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_host, PyObject *__pyx_v_port, PyObject *__pyx_v_connections_per_query, PyObject *__pyx_v_duration, PyObject *__pyx_v_queries) { - std::string __pyx_v_result; - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - std::string __pyx_t_1; - std::string __pyx_t_2; - int __pyx_t_3; - double __pyx_t_4; - std::vector<std::string> __pyx_t_5; - PyObject *__pyx_t_6 = NULL; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("benchmark", 0); - - /* "benchmark.pyx":17 - * ''' - * ''' - * result = benchmark_json(<const string&> host, <const string&> port, # <<<<<<<<<<<<<< - * <int> connections_per_query, <double> duration, - * <const vector[string]&> queries) - */ - __pyx_t_1 = __pyx_convert_string_from_py_std__in_string(__pyx_v_host); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 17; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __pyx_t_2 = __pyx_convert_string_from_py_std__in_string(__pyx_v_port); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 17; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - - /* "benchmark.pyx":18 - * ''' - * result = benchmark_json(<const string&> host, <const string&> port, - * <int> connections_per_query, <double> duration, # <<<<<<<<<<<<<< - * <const vector[string]&> queries) - * return result - */ - __pyx_t_3 = __Pyx_PyInt_As_int(__pyx_v_connections_per_query); if (unlikely((__pyx_t_3 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 18; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __pyx_t_4 = __pyx_PyFloat_AsDouble(__pyx_v_duration); if (unlikely((__pyx_t_4 == (double)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 18; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - - /* "benchmark.pyx":19 - * result = benchmark_json(<const string&> host, <const string&> port, - * <int> connections_per_query, <double> duration, - * <const vector[string]&> queries) # <<<<<<<<<<<<<< - * return result - */ - __pyx_t_5 = __pyx_convert_vector_from_py_std_3a__3a_string(__pyx_v_queries); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 19; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - - /* "benchmark.pyx":17 - * ''' - * ''' - * result = benchmark_json(<const string&> host, <const string&> port, # <<<<<<<<<<<<<< - * <int> connections_per_query, <double> duration, - * <const vector[string]&> queries) - */ - __pyx_v_result = benchmark_json(((std::string const &)__pyx_t_1), ((std::string const &)__pyx_t_2), ((int)__pyx_t_3), ((double)__pyx_t_4), ((std::vector<std::string> const &)__pyx_t_5)); - - /* "benchmark.pyx":20 - * <int> connections_per_query, <double> duration, - * <const vector[string]&> queries) - * return result # <<<<<<<<<<<<<< - */ - __Pyx_XDECREF(__pyx_r); - __pyx_t_6 = __pyx_convert_PyBytes_string_to_py_std__in_string(__pyx_v_result); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 20; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_6); - __pyx_r = __pyx_t_6; - __pyx_t_6 = 0; - goto __pyx_L0; - - /* "benchmark.pyx":14 - * - * - * def benchmark(host, port, connections_per_query, duration, queries): # <<<<<<<<<<<<<< - * ''' - * ''' - */ - - /* function exit code */ - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_6); - __Pyx_AddTraceback("benchmark.benchmark", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = NULL; - __pyx_L0:; - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "string.from_py":13 - * - * @cname("__pyx_convert_string_from_py_std__in_string") - * cdef string __pyx_convert_string_from_py_std__in_string(object o) except *: # <<<<<<<<<<<<<< - * cdef Py_ssize_t length - * cdef char* data = __Pyx_PyObject_AsStringAndSize(o, &length) - */ - -static std::string __pyx_convert_string_from_py_std__in_string(PyObject *__pyx_v_o) { - Py_ssize_t __pyx_v_length; - char *__pyx_v_data; - std::string __pyx_r; - __Pyx_RefNannyDeclarations - char *__pyx_t_1; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__pyx_convert_string_from_py_std__in_string", 0); - - /* "string.from_py":15 - * cdef string __pyx_convert_string_from_py_std__in_string(object o) except *: - * cdef Py_ssize_t length - * cdef char* data = __Pyx_PyObject_AsStringAndSize(o, &length) # <<<<<<<<<<<<<< - * return string(data, length) - * - */ - __pyx_t_1 = __Pyx_PyObject_AsStringAndSize(__pyx_v_o, (&__pyx_v_length)); if (unlikely(__pyx_t_1 == NULL)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 15; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __pyx_v_data = __pyx_t_1; - - /* "string.from_py":16 - * cdef Py_ssize_t length - * cdef char* data = __Pyx_PyObject_AsStringAndSize(o, &length) - * return string(data, length) # <<<<<<<<<<<<<< - * - * - */ - __pyx_r = std::string(__pyx_v_data, __pyx_v_length); - goto __pyx_L0; - - /* "string.from_py":13 - * - * @cname("__pyx_convert_string_from_py_std__in_string") - * cdef string __pyx_convert_string_from_py_std__in_string(object o) except *: # <<<<<<<<<<<<<< - * cdef Py_ssize_t length - * cdef char* data = __Pyx_PyObject_AsStringAndSize(o, &length) - */ - - /* function exit code */ - __pyx_L1_error:; - __Pyx_AddTraceback("string.from_py.__pyx_convert_string_from_py_std__in_string", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_L0:; - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "vector.from_py":50 - * - * @cname("__pyx_convert_vector_from_py_std_3a__3a_string") - * cdef vector[X] __pyx_convert_vector_from_py_std_3a__3a_string(object o) except *: # <<<<<<<<<<<<<< - * cdef vector[X] v - * for item in o: - */ - -static std::vector<std::string> __pyx_convert_vector_from_py_std_3a__3a_string(PyObject *__pyx_v_o) { - std::vector<std::string> __pyx_v_v; - PyObject *__pyx_v_item = NULL; - std::vector<std::string> __pyx_r; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - Py_ssize_t __pyx_t_2; - PyObject *(*__pyx_t_3)(PyObject *); - PyObject *__pyx_t_4 = NULL; - std::string __pyx_t_5; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__pyx_convert_vector_from_py_std_3a__3a_string", 0); - - /* "vector.from_py":52 - * cdef vector[X] __pyx_convert_vector_from_py_std_3a__3a_string(object o) except *: - * cdef vector[X] v - * for item in o: # <<<<<<<<<<<<<< - * v.push_back(X_from_py(item)) - * return v - */ - if (likely(PyList_CheckExact(__pyx_v_o)) || PyTuple_CheckExact(__pyx_v_o)) { - __pyx_t_1 = __pyx_v_o; __Pyx_INCREF(__pyx_t_1); __pyx_t_2 = 0; - __pyx_t_3 = NULL; - } else { - __pyx_t_2 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_v_o); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 52; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_3 = Py_TYPE(__pyx_t_1)->tp_iternext; if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 52; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - } - for (;;) { - if (likely(!__pyx_t_3)) { - if (likely(PyList_CheckExact(__pyx_t_1))) { - if (__pyx_t_2 >= PyList_GET_SIZE(__pyx_t_1)) break; - #if CYTHON_COMPILING_IN_CPYTHON - __pyx_t_4 = PyList_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++; if (unlikely(0 < 0)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 52; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - #else - __pyx_t_4 = PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 52; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_4); - #endif - } else { - if (__pyx_t_2 >= PyTuple_GET_SIZE(__pyx_t_1)) break; - #if CYTHON_COMPILING_IN_CPYTHON - __pyx_t_4 = PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_2); __Pyx_INCREF(__pyx_t_4); __pyx_t_2++; if (unlikely(0 < 0)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 52; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - #else - __pyx_t_4 = PySequence_ITEM(__pyx_t_1, __pyx_t_2); __pyx_t_2++; if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 52; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_4); - #endif - } - } else { - __pyx_t_4 = __pyx_t_3(__pyx_t_1); - if (unlikely(!__pyx_t_4)) { - PyObject* exc_type = PyErr_Occurred(); - if (exc_type) { - if (likely(exc_type == PyExc_StopIteration || PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear(); - else {__pyx_filename = __pyx_f[1]; __pyx_lineno = 52; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - } - break; - } - __Pyx_GOTREF(__pyx_t_4); - } - __Pyx_XDECREF_SET(__pyx_v_item, __pyx_t_4); - __pyx_t_4 = 0; - - /* "vector.from_py":53 - * cdef vector[X] v - * for item in o: - * v.push_back(X_from_py(item)) # <<<<<<<<<<<<<< - * return v - * - */ - __pyx_t_5 = __pyx_convert_string_from_py_std__in_string(__pyx_v_item); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 53; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __pyx_v_v.push_back(__pyx_t_5); - - /* "vector.from_py":52 - * cdef vector[X] __pyx_convert_vector_from_py_std_3a__3a_string(object o) except *: - * cdef vector[X] v - * for item in o: # <<<<<<<<<<<<<< - * v.push_back(X_from_py(item)) - * return v - */ - } - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - - /* "vector.from_py":54 - * for item in o: - * v.push_back(X_from_py(item)) - * return v # <<<<<<<<<<<<<< - * - * - */ - __pyx_r = __pyx_v_v; - goto __pyx_L0; - - /* "vector.from_py":50 - * - * @cname("__pyx_convert_vector_from_py_std_3a__3a_string") - * cdef vector[X] __pyx_convert_vector_from_py_std_3a__3a_string(object o) except *: # <<<<<<<<<<<<<< - * cdef vector[X] v - * for item in o: - */ - - /* function exit code */ - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_4); - __Pyx_AddTraceback("vector.from_py.__pyx_convert_vector_from_py_std_3a__3a_string", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_L0:; - __Pyx_XDECREF(__pyx_v_item); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "string.to_py":31 - * - * @cname("__pyx_convert_PyObject_string_to_py_std__in_string") - * cdef inline object __pyx_convert_PyObject_string_to_py_std__in_string(const string& s): # <<<<<<<<<<<<<< - * return __Pyx_PyObject_FromStringAndSize(s.data(), s.size()) - * cdef extern from *: - */ - -static CYTHON_INLINE PyObject *__pyx_convert_PyObject_string_to_py_std__in_string(std::string const &__pyx_v_s) { - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__pyx_convert_PyObject_string_to_py_std__in_string", 0); - - /* "string.to_py":32 - * @cname("__pyx_convert_PyObject_string_to_py_std__in_string") - * cdef inline object __pyx_convert_PyObject_string_to_py_std__in_string(const string& s): - * return __Pyx_PyObject_FromStringAndSize(s.data(), s.size()) # <<<<<<<<<<<<<< - * cdef extern from *: - * cdef object __Pyx_PyUnicode_FromStringAndSize(char*, size_t) - */ - __Pyx_XDECREF(__pyx_r); - __pyx_t_1 = __Pyx_PyObject_FromStringAndSize(__pyx_v_s.data(), __pyx_v_s.size()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 32; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - - /* "string.to_py":31 - * - * @cname("__pyx_convert_PyObject_string_to_py_std__in_string") - * cdef inline object __pyx_convert_PyObject_string_to_py_std__in_string(const string& s): # <<<<<<<<<<<<<< - * return __Pyx_PyObject_FromStringAndSize(s.data(), s.size()) - * cdef extern from *: - */ - - /* function exit code */ - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_AddTraceback("string.to_py.__pyx_convert_PyObject_string_to_py_std__in_string", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = 0; - __pyx_L0:; - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "string.to_py":37 - * - * @cname("__pyx_convert_PyUnicode_string_to_py_std__in_string") - * cdef inline object __pyx_convert_PyUnicode_string_to_py_std__in_string(const string& s): # <<<<<<<<<<<<<< - * return __Pyx_PyUnicode_FromStringAndSize(s.data(), s.size()) - * cdef extern from *: - */ - -static CYTHON_INLINE PyObject *__pyx_convert_PyUnicode_string_to_py_std__in_string(std::string const &__pyx_v_s) { - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__pyx_convert_PyUnicode_string_to_py_std__in_string", 0); - - /* "string.to_py":38 - * @cname("__pyx_convert_PyUnicode_string_to_py_std__in_string") - * cdef inline object __pyx_convert_PyUnicode_string_to_py_std__in_string(const string& s): - * return __Pyx_PyUnicode_FromStringAndSize(s.data(), s.size()) # <<<<<<<<<<<<<< - * cdef extern from *: - * cdef object __Pyx_PyStr_FromStringAndSize(char*, size_t) - */ - __Pyx_XDECREF(__pyx_r); - __pyx_t_1 = __Pyx_PyUnicode_FromStringAndSize(__pyx_v_s.data(), __pyx_v_s.size()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 38; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - - /* "string.to_py":37 - * - * @cname("__pyx_convert_PyUnicode_string_to_py_std__in_string") - * cdef inline object __pyx_convert_PyUnicode_string_to_py_std__in_string(const string& s): # <<<<<<<<<<<<<< - * return __Pyx_PyUnicode_FromStringAndSize(s.data(), s.size()) - * cdef extern from *: - */ - - /* function exit code */ - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_AddTraceback("string.to_py.__pyx_convert_PyUnicode_string_to_py_std__in_string", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = 0; - __pyx_L0:; - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "string.to_py":43 - * - * @cname("__pyx_convert_PyStr_string_to_py_std__in_string") - * cdef inline object __pyx_convert_PyStr_string_to_py_std__in_string(const string& s): # <<<<<<<<<<<<<< - * return __Pyx_PyStr_FromStringAndSize(s.data(), s.size()) - * cdef extern from *: - */ - -static CYTHON_INLINE PyObject *__pyx_convert_PyStr_string_to_py_std__in_string(std::string const &__pyx_v_s) { - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__pyx_convert_PyStr_string_to_py_std__in_string", 0); - - /* "string.to_py":44 - * @cname("__pyx_convert_PyStr_string_to_py_std__in_string") - * cdef inline object __pyx_convert_PyStr_string_to_py_std__in_string(const string& s): - * return __Pyx_PyStr_FromStringAndSize(s.data(), s.size()) # <<<<<<<<<<<<<< - * cdef extern from *: - * cdef object __Pyx_PyBytes_FromStringAndSize(char*, size_t) - */ - __Pyx_XDECREF(__pyx_r); - __pyx_t_1 = __Pyx_PyStr_FromStringAndSize(__pyx_v_s.data(), __pyx_v_s.size()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 44; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - - /* "string.to_py":43 - * - * @cname("__pyx_convert_PyStr_string_to_py_std__in_string") - * cdef inline object __pyx_convert_PyStr_string_to_py_std__in_string(const string& s): # <<<<<<<<<<<<<< - * return __Pyx_PyStr_FromStringAndSize(s.data(), s.size()) - * cdef extern from *: - */ - - /* function exit code */ - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_AddTraceback("string.to_py.__pyx_convert_PyStr_string_to_py_std__in_string", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = 0; - __pyx_L0:; - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "string.to_py":49 - * - * @cname("__pyx_convert_PyBytes_string_to_py_std__in_string") - * cdef inline object __pyx_convert_PyBytes_string_to_py_std__in_string(const string& s): # <<<<<<<<<<<<<< - * return __Pyx_PyBytes_FromStringAndSize(s.data(), s.size()) - * cdef extern from *: - */ - -static CYTHON_INLINE PyObject *__pyx_convert_PyBytes_string_to_py_std__in_string(std::string const &__pyx_v_s) { - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__pyx_convert_PyBytes_string_to_py_std__in_string", 0); - - /* "string.to_py":50 - * @cname("__pyx_convert_PyBytes_string_to_py_std__in_string") - * cdef inline object __pyx_convert_PyBytes_string_to_py_std__in_string(const string& s): - * return __Pyx_PyBytes_FromStringAndSize(s.data(), s.size()) # <<<<<<<<<<<<<< - * cdef extern from *: - * cdef object __Pyx_PyByteArray_FromStringAndSize(char*, size_t) - */ - __Pyx_XDECREF(__pyx_r); - __pyx_t_1 = __Pyx_PyBytes_FromStringAndSize(__pyx_v_s.data(), __pyx_v_s.size()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - - /* "string.to_py":49 - * - * @cname("__pyx_convert_PyBytes_string_to_py_std__in_string") - * cdef inline object __pyx_convert_PyBytes_string_to_py_std__in_string(const string& s): # <<<<<<<<<<<<<< - * return __Pyx_PyBytes_FromStringAndSize(s.data(), s.size()) - * cdef extern from *: - */ - - /* function exit code */ - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_AddTraceback("string.to_py.__pyx_convert_PyBytes_string_to_py_std__in_string", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = 0; - __pyx_L0:; - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "string.to_py":55 - * - * @cname("__pyx_convert_PyByteArray_string_to_py_std__in_string") - * cdef inline object __pyx_convert_PyByteArray_string_to_py_std__in_string(const string& s): # <<<<<<<<<<<<<< - * return __Pyx_PyByteArray_FromStringAndSize(s.data(), s.size()) - * - */ - -static CYTHON_INLINE PyObject *__pyx_convert_PyByteArray_string_to_py_std__in_string(std::string const &__pyx_v_s) { - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__pyx_convert_PyByteArray_string_to_py_std__in_string", 0); - - /* "string.to_py":56 - * @cname("__pyx_convert_PyByteArray_string_to_py_std__in_string") - * cdef inline object __pyx_convert_PyByteArray_string_to_py_std__in_string(const string& s): - * return __Pyx_PyByteArray_FromStringAndSize(s.data(), s.size()) # <<<<<<<<<<<<<< - * - */ - __Pyx_XDECREF(__pyx_r); - __pyx_t_1 = __Pyx_PyByteArray_FromStringAndSize(__pyx_v_s.data(), __pyx_v_s.size()); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 56; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_1); - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - - /* "string.to_py":55 - * - * @cname("__pyx_convert_PyByteArray_string_to_py_std__in_string") - * cdef inline object __pyx_convert_PyByteArray_string_to_py_std__in_string(const string& s): # <<<<<<<<<<<<<< - * return __Pyx_PyByteArray_FromStringAndSize(s.data(), s.size()) - * - */ - - /* function exit code */ - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_AddTraceback("string.to_py.__pyx_convert_PyByteArray_string_to_py_std__in_string", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = 0; - __pyx_L0:; - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -static PyMethodDef __pyx_methods[] = { - {0, 0, 0, 0} -}; - -#if PY_MAJOR_VERSION >= 3 -static struct PyModuleDef __pyx_moduledef = { - #if PY_VERSION_HEX < 0x03020000 - { PyObject_HEAD_INIT(NULL) NULL, 0, NULL }, - #else - PyModuleDef_HEAD_INIT, - #endif - "benchmark", - 0, /* m_doc */ - -1, /* m_size */ - __pyx_methods /* m_methods */, - NULL, /* m_reload */ - NULL, /* m_traverse */ - NULL, /* m_clear */ - NULL /* m_free */ -}; -#endif - -static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_n_s_benchmark, __pyx_k_benchmark, sizeof(__pyx_k_benchmark), 0, 0, 1, 1}, - {&__pyx_n_s_connections_per_query, __pyx_k_connections_per_query, sizeof(__pyx_k_connections_per_query), 0, 0, 1, 1}, - {&__pyx_n_s_duration, __pyx_k_duration, sizeof(__pyx_k_duration), 0, 0, 1, 1}, - {&__pyx_kp_s_home_buda_Local_memgraph_demo_w, __pyx_k_home_buda_Local_memgraph_demo_w, sizeof(__pyx_k_home_buda_Local_memgraph_demo_w), 0, 0, 1, 0}, - {&__pyx_n_s_host, __pyx_k_host, sizeof(__pyx_k_host), 0, 0, 1, 1}, - {&__pyx_n_s_main, __pyx_k_main, sizeof(__pyx_k_main), 0, 0, 1, 1}, - {&__pyx_n_s_port, __pyx_k_port, sizeof(__pyx_k_port), 0, 0, 1, 1}, - {&__pyx_n_s_queries, __pyx_k_queries, sizeof(__pyx_k_queries), 0, 0, 1, 1}, - {&__pyx_n_s_result, __pyx_k_result, sizeof(__pyx_k_result), 0, 0, 1, 1}, - {&__pyx_n_s_test, __pyx_k_test, sizeof(__pyx_k_test), 0, 0, 1, 1}, - {0, 0, 0, 0, 0, 0, 0} -}; -static int __Pyx_InitCachedBuiltins(void) { - return 0; -} - -static int __Pyx_InitCachedConstants(void) { - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("__Pyx_InitCachedConstants", 0); - - /* "benchmark.pyx":14 - * - * - * def benchmark(host, port, connections_per_query, duration, queries): # <<<<<<<<<<<<<< - * ''' - * ''' - */ - __pyx_tuple_ = PyTuple_Pack(6, __pyx_n_s_host, __pyx_n_s_port, __pyx_n_s_connections_per_query, __pyx_n_s_duration, __pyx_n_s_queries, __pyx_n_s_result); if (unlikely(!__pyx_tuple_)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 14; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_tuple_); - __Pyx_GIVEREF(__pyx_tuple_); - __pyx_codeobj__2 = (PyObject*)__Pyx_PyCode_New(5, 0, 6, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple_, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_buda_Local_memgraph_demo_w, __pyx_n_s_benchmark, 14, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 14; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_RefNannyFinishContext(); - return 0; - __pyx_L1_error:; - __Pyx_RefNannyFinishContext(); - return -1; -} - -static int __Pyx_InitGlobals(void) { - if (__Pyx_InitStrings(__pyx_string_tab) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; - return 0; - __pyx_L1_error:; - return -1; -} - -#if PY_MAJOR_VERSION < 3 -PyMODINIT_FUNC initbenchmark(void); /*proto*/ -PyMODINIT_FUNC initbenchmark(void) -#else -PyMODINIT_FUNC PyInit_benchmark(void); /*proto*/ -PyMODINIT_FUNC PyInit_benchmark(void) -#endif -{ - PyObject *__pyx_t_1 = NULL; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannyDeclarations - #if CYTHON_REFNANNY - __Pyx_RefNanny = __Pyx_RefNannyImportAPI("refnanny"); - if (!__Pyx_RefNanny) { - PyErr_Clear(); - __Pyx_RefNanny = __Pyx_RefNannyImportAPI("Cython.Runtime.refnanny"); - if (!__Pyx_RefNanny) - Py_FatalError("failed to import 'refnanny' module"); - } - #endif - __Pyx_RefNannySetupContext("PyMODINIT_FUNC PyInit_benchmark(void)", 0); - if (__Pyx_check_binary_version() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __pyx_empty_tuple = PyTuple_New(0); if (unlikely(!__pyx_empty_tuple)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __pyx_empty_bytes = PyBytes_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_bytes)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - #ifdef __Pyx_CyFunction_USED - if (__pyx_CyFunction_init() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - #endif - #ifdef __Pyx_FusedFunction_USED - if (__pyx_FusedFunction_init() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - #endif - #ifdef __Pyx_Coroutine_USED - if (__pyx_Coroutine_init() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - #endif - #ifdef __Pyx_Generator_USED - if (__pyx_Generator_init() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - #endif - #ifdef __Pyx_StopAsyncIteration_USED - if (__pyx_StopAsyncIteration_init() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - #endif - /*--- Library function declarations ---*/ - /*--- Threads initialization code ---*/ - #if defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS - #ifdef WITH_THREAD /* Python build with threading support? */ - PyEval_InitThreads(); - #endif - #endif - /*--- Module creation code ---*/ - #if PY_MAJOR_VERSION < 3 - __pyx_m = Py_InitModule4("benchmark", __pyx_methods, 0, 0, PYTHON_API_VERSION); Py_XINCREF(__pyx_m); - #else - __pyx_m = PyModule_Create(&__pyx_moduledef); - #endif - if (unlikely(!__pyx_m)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __pyx_d = PyModule_GetDict(__pyx_m); if (unlikely(!__pyx_d)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - Py_INCREF(__pyx_d); - __pyx_b = PyImport_AddModule(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_b)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - #if CYTHON_COMPILING_IN_PYPY - Py_INCREF(__pyx_b); - #endif - if (PyObject_SetAttrString(__pyx_m, "__builtins__", __pyx_b) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;}; - /*--- Initialize various global constants etc. ---*/ - if (__Pyx_InitGlobals() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - #if PY_MAJOR_VERSION < 3 && (__PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT) - if (__Pyx_init_sys_getdefaultencoding_params() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - #endif - if (__pyx_module_is_main_benchmark) { - if (PyObject_SetAttrString(__pyx_m, "__name__", __pyx_n_s_main) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - } - #if PY_MAJOR_VERSION >= 3 - { - PyObject *modules = PyImport_GetModuleDict(); if (unlikely(!modules)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - if (!PyDict_GetItemString(modules, "benchmark")) { - if (unlikely(PyDict_SetItemString(modules, "benchmark", __pyx_m) < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - } - } - #endif - /*--- Builtin init code ---*/ - if (__Pyx_InitCachedBuiltins() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - /*--- Constants init code ---*/ - if (__Pyx_InitCachedConstants() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - /*--- Global init code ---*/ - /*--- Variable export code ---*/ - /*--- Function export code ---*/ - /*--- Type init code ---*/ - /*--- Type import code ---*/ - /*--- Variable import code ---*/ - /*--- Function import code ---*/ - /*--- Execution code ---*/ - #if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED) - if (__Pyx_patch_abc() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - #endif - - /* "benchmark.pyx":14 - * - * - * def benchmark(host, port, connections_per_query, duration, queries): # <<<<<<<<<<<<<< - * ''' - * ''' - */ - __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_9benchmark_1benchmark, NULL, __pyx_n_s_benchmark); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 14; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_1); - if (PyDict_SetItem(__pyx_d, __pyx_n_s_benchmark, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 14; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - - /* "benchmark.pyx":1 - * # -*- coding: utf-8 -*- # <<<<<<<<<<<<<< - * - * from libcpp.string cimport string - */ - __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_1); - if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - - /* "string.to_py":55 - * - * @cname("__pyx_convert_PyByteArray_string_to_py_std__in_string") - * cdef inline object __pyx_convert_PyByteArray_string_to_py_std__in_string(const string& s): # <<<<<<<<<<<<<< - * return __Pyx_PyByteArray_FromStringAndSize(s.data(), s.size()) - * - */ - - /*--- Wrapped vars code ---*/ - - goto __pyx_L0; - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - if (__pyx_m) { - if (__pyx_d) { - __Pyx_AddTraceback("init benchmark", __pyx_clineno, __pyx_lineno, __pyx_filename); - } - Py_DECREF(__pyx_m); __pyx_m = 0; - } else if (!PyErr_Occurred()) { - PyErr_SetString(PyExc_ImportError, "init benchmark"); - } - __pyx_L0:; - __Pyx_RefNannyFinishContext(); - #if PY_MAJOR_VERSION < 3 - return; - #else - return __pyx_m; - #endif -} - -/* --- Runtime support code --- */ -#if CYTHON_REFNANNY -static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname) { - PyObject *m = NULL, *p = NULL; - void *r = NULL; - m = PyImport_ImportModule((char *)modname); - if (!m) goto end; - p = PyObject_GetAttrString(m, (char *)"RefNannyAPI"); - if (!p) goto end; - r = PyLong_AsVoidPtr(p); -end: - Py_XDECREF(p); - Py_XDECREF(m); - return (__Pyx_RefNannyAPIStruct *)r; -} -#endif - -static void __Pyx_RaiseArgtupleInvalid( - const char* func_name, - int exact, - Py_ssize_t num_min, - Py_ssize_t num_max, - Py_ssize_t num_found) -{ - Py_ssize_t num_expected; - const char *more_or_less; - if (num_found < num_min) { - num_expected = num_min; - more_or_less = "at least"; - } else { - num_expected = num_max; - more_or_less = "at most"; - } - if (exact) { - more_or_less = "exactly"; - } - PyErr_Format(PyExc_TypeError, - "%.200s() takes %.8s %" CYTHON_FORMAT_SSIZE_T "d positional argument%.1s (%" CYTHON_FORMAT_SSIZE_T "d given)", - func_name, more_or_less, num_expected, - (num_expected == 1) ? "" : "s", num_found); -} - -static void __Pyx_RaiseDoubleKeywordsError( - const char* func_name, - PyObject* kw_name) -{ - PyErr_Format(PyExc_TypeError, - #if PY_MAJOR_VERSION >= 3 - "%s() got multiple values for keyword argument '%U'", func_name, kw_name); - #else - "%s() got multiple values for keyword argument '%s'", func_name, - PyString_AsString(kw_name)); - #endif -} - -static int __Pyx_ParseOptionalKeywords( - PyObject *kwds, - PyObject **argnames[], - PyObject *kwds2, - PyObject *values[], - Py_ssize_t num_pos_args, - const char* function_name) -{ - PyObject *key = 0, *value = 0; - Py_ssize_t pos = 0; - PyObject*** name; - PyObject*** first_kw_arg = argnames + num_pos_args; - while (PyDict_Next(kwds, &pos, &key, &value)) { - name = first_kw_arg; - while (*name && (**name != key)) name++; - if (*name) { - values[name-argnames] = value; - continue; - } - name = first_kw_arg; - #if PY_MAJOR_VERSION < 3 - if (likely(PyString_CheckExact(key)) || likely(PyString_Check(key))) { - while (*name) { - if ((CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**name) == PyString_GET_SIZE(key)) - && _PyString_Eq(**name, key)) { - values[name-argnames] = value; - break; - } - name++; - } - if (*name) continue; - else { - PyObject*** argname = argnames; - while (argname != first_kw_arg) { - if ((**argname == key) || ( - (CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**argname) == PyString_GET_SIZE(key)) - && _PyString_Eq(**argname, key))) { - goto arg_passed_twice; - } - argname++; - } - } - } else - #endif - if (likely(PyUnicode_Check(key))) { - while (*name) { - int cmp = (**name == key) ? 0 : - #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 - (PyUnicode_GET_SIZE(**name) != PyUnicode_GET_SIZE(key)) ? 1 : - #endif - PyUnicode_Compare(**name, key); - if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; - if (cmp == 0) { - values[name-argnames] = value; - break; - } - name++; - } - if (*name) continue; - else { - PyObject*** argname = argnames; - while (argname != first_kw_arg) { - int cmp = (**argname == key) ? 0 : - #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 - (PyUnicode_GET_SIZE(**argname) != PyUnicode_GET_SIZE(key)) ? 1 : - #endif - PyUnicode_Compare(**argname, key); - if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; - if (cmp == 0) goto arg_passed_twice; - argname++; - } - } - } else - goto invalid_keyword_type; - if (kwds2) { - if (unlikely(PyDict_SetItem(kwds2, key, value))) goto bad; - } else { - goto invalid_keyword; - } - } - return 0; -arg_passed_twice: - __Pyx_RaiseDoubleKeywordsError(function_name, key); - goto bad; -invalid_keyword_type: - PyErr_Format(PyExc_TypeError, - "%.200s() keywords must be strings", function_name); - goto bad; -invalid_keyword: - PyErr_Format(PyExc_TypeError, - #if PY_MAJOR_VERSION < 3 - "%.200s() got an unexpected keyword argument '%.200s'", - function_name, PyString_AsString(key)); - #else - "%s() got an unexpected keyword argument '%U'", - function_name, key); - #endif -bad: - return -1; -} - -static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line) { - int start = 0, mid = 0, end = count - 1; - if (end >= 0 && code_line > entries[end].code_line) { - return count; - } - while (start < end) { - mid = start + (end - start) / 2; - if (code_line < entries[mid].code_line) { - end = mid; - } else if (code_line > entries[mid].code_line) { - start = mid + 1; - } else { - return mid; - } - } - if (code_line <= entries[mid].code_line) { - return mid; - } else { - return mid + 1; - } -} -static PyCodeObject *__pyx_find_code_object(int code_line) { - PyCodeObject* code_object; - int pos; - if (unlikely(!code_line) || unlikely(!__pyx_code_cache.entries)) { - return NULL; - } - pos = __pyx_bisect_code_objects(__pyx_code_cache.entries, __pyx_code_cache.count, code_line); - if (unlikely(pos >= __pyx_code_cache.count) || unlikely(__pyx_code_cache.entries[pos].code_line != code_line)) { - return NULL; - } - code_object = __pyx_code_cache.entries[pos].code_object; - Py_INCREF(code_object); - return code_object; -} -static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { - int pos, i; - __Pyx_CodeObjectCacheEntry* entries = __pyx_code_cache.entries; - if (unlikely(!code_line)) { - return; - } - if (unlikely(!entries)) { - entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Malloc(64*sizeof(__Pyx_CodeObjectCacheEntry)); - if (likely(entries)) { - __pyx_code_cache.entries = entries; - __pyx_code_cache.max_count = 64; - __pyx_code_cache.count = 1; - entries[0].code_line = code_line; - entries[0].code_object = code_object; - Py_INCREF(code_object); - } - return; - } - pos = __pyx_bisect_code_objects(__pyx_code_cache.entries, __pyx_code_cache.count, code_line); - if ((pos < __pyx_code_cache.count) && unlikely(__pyx_code_cache.entries[pos].code_line == code_line)) { - PyCodeObject* tmp = entries[pos].code_object; - entries[pos].code_object = code_object; - Py_DECREF(tmp); - return; - } - if (__pyx_code_cache.count == __pyx_code_cache.max_count) { - int new_max = __pyx_code_cache.max_count + 64; - entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Realloc( - __pyx_code_cache.entries, (size_t)new_max*sizeof(__Pyx_CodeObjectCacheEntry)); - if (unlikely(!entries)) { - return; - } - __pyx_code_cache.entries = entries; - __pyx_code_cache.max_count = new_max; - } - for (i=__pyx_code_cache.count; i>pos; i--) { - entries[i] = entries[i-1]; - } - entries[pos].code_line = code_line; - entries[pos].code_object = code_object; - __pyx_code_cache.count++; - Py_INCREF(code_object); -} - -#include "compile.h" -#include "frameobject.h" -#include "traceback.h" -static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - const char *funcname, int c_line, - int py_line, const char *filename) { - PyCodeObject *py_code = 0; - PyObject *py_srcfile = 0; - PyObject *py_funcname = 0; - #if PY_MAJOR_VERSION < 3 - py_srcfile = PyString_FromString(filename); - #else - py_srcfile = PyUnicode_FromString(filename); - #endif - if (!py_srcfile) goto bad; - if (c_line) { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); - #else - py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); - #endif - } - else { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromString(funcname); - #else - py_funcname = PyUnicode_FromString(funcname); - #endif - } - if (!py_funcname) goto bad; - py_code = __Pyx_PyCode_New( - 0, - 0, - 0, - 0, - 0, - __pyx_empty_bytes, /*PyObject *code,*/ - __pyx_empty_tuple, /*PyObject *consts,*/ - __pyx_empty_tuple, /*PyObject *names,*/ - __pyx_empty_tuple, /*PyObject *varnames,*/ - __pyx_empty_tuple, /*PyObject *freevars,*/ - __pyx_empty_tuple, /*PyObject *cellvars,*/ - py_srcfile, /*PyObject *filename,*/ - py_funcname, /*PyObject *name,*/ - py_line, - __pyx_empty_bytes /*PyObject *lnotab*/ - ); - Py_DECREF(py_srcfile); - Py_DECREF(py_funcname); - return py_code; -bad: - Py_XDECREF(py_srcfile); - Py_XDECREF(py_funcname); - return NULL; -} -static void __Pyx_AddTraceback(const char *funcname, int c_line, - int py_line, const char *filename) { - PyCodeObject *py_code = 0; - PyFrameObject *py_frame = 0; - py_code = __pyx_find_code_object(c_line ? c_line : py_line); - if (!py_code) { - py_code = __Pyx_CreateCodeObjectForTraceback( - funcname, c_line, py_line, filename); - if (!py_code) goto bad; - __pyx_insert_code_object(c_line ? c_line : py_line, py_code); - } - py_frame = PyFrame_New( - PyThreadState_GET(), /*PyThreadState *tstate,*/ - py_code, /*PyCodeObject *code,*/ - __pyx_d, /*PyObject *globals,*/ - 0 /*PyObject *locals*/ - ); - if (!py_frame) goto bad; - py_frame->f_lineno = py_line; - PyTraceBack_Here(py_frame); -bad: - Py_XDECREF(py_code); - Py_XDECREF(py_frame); -} - -#define __PYX_VERIFY_RETURN_INT(target_type, func_type, func_value)\ - __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 0) -#define __PYX_VERIFY_RETURN_INT_EXC(target_type, func_type, func_value)\ - __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 1) -#define __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, exc)\ - {\ - func_type value = func_value;\ - if (sizeof(target_type) < sizeof(func_type)) {\ - if (unlikely(value != (func_type) (target_type) value)) {\ - func_type zero = 0;\ - if (exc && unlikely(value == (func_type)-1 && PyErr_Occurred()))\ - return (target_type) -1;\ - if (is_unsigned && unlikely(value < zero))\ - goto raise_neg_overflow;\ - else\ - goto raise_overflow;\ - }\ - }\ - return (target_type) value;\ - } - -#if CYTHON_USE_PYLONG_INTERNALS - #include "longintrepr.h" -#endif - -static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { - const int neg_one = (int) -1, const_zero = (int) 0; - const int is_unsigned = neg_one > const_zero; -#if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { - if (sizeof(int) < sizeof(long)) { - __PYX_VERIFY_RETURN_INT(int, long, PyInt_AS_LONG(x)) - } else { - long val = PyInt_AS_LONG(x); - if (is_unsigned && unlikely(val < 0)) { - goto raise_neg_overflow; - } - return (int) val; - } - } else -#endif - if (likely(PyLong_Check(x))) { - if (is_unsigned) { -#if CYTHON_USE_PYLONG_INTERNALS - const digit* digits = ((PyLongObject*)x)->ob_digit; - switch (Py_SIZE(x)) { - case 0: return (int) 0; - case 1: __PYX_VERIFY_RETURN_INT(int, digit, digits[0]) - case 2: - if (8 * sizeof(int) > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(int) >= 2 * PyLong_SHIFT) { - return (int) (((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); - } - } - break; - case 3: - if (8 * sizeof(int) > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(int) >= 3 * PyLong_SHIFT) { - return (int) (((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); - } - } - break; - case 4: - if (8 * sizeof(int) > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(int) >= 4 * PyLong_SHIFT) { - return (int) (((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); - } - } - break; - } -#endif -#if CYTHON_COMPILING_IN_CPYTHON - if (unlikely(Py_SIZE(x) < 0)) { - goto raise_neg_overflow; - } -#else - { - int result = PyObject_RichCompareBool(x, Py_False, Py_LT); - if (unlikely(result < 0)) - return (int) -1; - if (unlikely(result == 1)) - goto raise_neg_overflow; - } -#endif - if (sizeof(int) <= sizeof(unsigned long)) { - __PYX_VERIFY_RETURN_INT_EXC(int, unsigned long, PyLong_AsUnsignedLong(x)) - } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { - __PYX_VERIFY_RETURN_INT_EXC(int, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) - } - } else { -#if CYTHON_USE_PYLONG_INTERNALS - const digit* digits = ((PyLongObject*)x)->ob_digit; - switch (Py_SIZE(x)) { - case 0: return (int) 0; - case -1: __PYX_VERIFY_RETURN_INT(int, sdigit, -(sdigit) digits[0]) - case 1: __PYX_VERIFY_RETURN_INT(int, digit, +digits[0]) - case -2: - if (8 * sizeof(int) - 1 > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { - return (int) (((int)-1)*(((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case 2: - if (8 * sizeof(int) > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { - return (int) ((((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case -3: - if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { - return (int) (((int)-1)*(((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case 3: - if (8 * sizeof(int) > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { - return (int) ((((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case -4: - if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { - return (int) (((int)-1)*(((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case 4: - if (8 * sizeof(int) > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { - return (int) ((((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - } -#endif - if (sizeof(int) <= sizeof(long)) { - __PYX_VERIFY_RETURN_INT_EXC(int, long, PyLong_AsLong(x)) - } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { - __PYX_VERIFY_RETURN_INT_EXC(int, PY_LONG_LONG, PyLong_AsLongLong(x)) - } - } - { -#if CYTHON_COMPILING_IN_PYPY && !defined(_PyLong_AsByteArray) - PyErr_SetString(PyExc_RuntimeError, - "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); -#else - int val; - PyObject *v = __Pyx_PyNumber_Int(x); - #if PY_MAJOR_VERSION < 3 - if (likely(v) && !PyLong_Check(v)) { - PyObject *tmp = v; - v = PyNumber_Long(tmp); - Py_DECREF(tmp); - } - #endif - if (likely(v)) { - int one = 1; int is_little = (int)*(unsigned char *)&one; - unsigned char *bytes = (unsigned char *)&val; - int ret = _PyLong_AsByteArray((PyLongObject *)v, - bytes, sizeof(val), - is_little, !is_unsigned); - Py_DECREF(v); - if (likely(!ret)) - return val; - } -#endif - return (int) -1; - } - } else { - int val; - PyObject *tmp = __Pyx_PyNumber_Int(x); - if (!tmp) return (int) -1; - val = __Pyx_PyInt_As_int(tmp); - Py_DECREF(tmp); - return val; - } -raise_overflow: - PyErr_SetString(PyExc_OverflowError, - "value too large to convert to int"); - return (int) -1; -raise_neg_overflow: - PyErr_SetString(PyExc_OverflowError, - "can't convert negative value to int"); - return (int) -1; -} - -static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { - const long neg_one = (long) -1, const_zero = (long) 0; - const int is_unsigned = neg_one > const_zero; - if (is_unsigned) { - if (sizeof(long) < sizeof(long)) { - return PyInt_FromLong((long) value); - } else if (sizeof(long) <= sizeof(unsigned long)) { - return PyLong_FromUnsignedLong((unsigned long) value); - } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { - return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); - } - } else { - if (sizeof(long) <= sizeof(long)) { - return PyInt_FromLong((long) value); - } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { - return PyLong_FromLongLong((PY_LONG_LONG) value); - } - } - { - int one = 1; int little = (int)*(unsigned char *)&one; - unsigned char *bytes = (unsigned char *)&value; - return _PyLong_FromByteArray(bytes, sizeof(long), - little, !is_unsigned); - } -} - -static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { - const long neg_one = (long) -1, const_zero = (long) 0; - const int is_unsigned = neg_one > const_zero; -#if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { - if (sizeof(long) < sizeof(long)) { - __PYX_VERIFY_RETURN_INT(long, long, PyInt_AS_LONG(x)) - } else { - long val = PyInt_AS_LONG(x); - if (is_unsigned && unlikely(val < 0)) { - goto raise_neg_overflow; - } - return (long) val; - } - } else -#endif - if (likely(PyLong_Check(x))) { - if (is_unsigned) { -#if CYTHON_USE_PYLONG_INTERNALS - const digit* digits = ((PyLongObject*)x)->ob_digit; - switch (Py_SIZE(x)) { - case 0: return (long) 0; - case 1: __PYX_VERIFY_RETURN_INT(long, digit, digits[0]) - case 2: - if (8 * sizeof(long) > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(long) >= 2 * PyLong_SHIFT) { - return (long) (((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); - } - } - break; - case 3: - if (8 * sizeof(long) > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(long) >= 3 * PyLong_SHIFT) { - return (long) (((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); - } - } - break; - case 4: - if (8 * sizeof(long) > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(long) >= 4 * PyLong_SHIFT) { - return (long) (((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); - } - } - break; - } -#endif -#if CYTHON_COMPILING_IN_CPYTHON - if (unlikely(Py_SIZE(x) < 0)) { - goto raise_neg_overflow; - } -#else - { - int result = PyObject_RichCompareBool(x, Py_False, Py_LT); - if (unlikely(result < 0)) - return (long) -1; - if (unlikely(result == 1)) - goto raise_neg_overflow; - } -#endif - if (sizeof(long) <= sizeof(unsigned long)) { - __PYX_VERIFY_RETURN_INT_EXC(long, unsigned long, PyLong_AsUnsignedLong(x)) - } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { - __PYX_VERIFY_RETURN_INT_EXC(long, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) - } - } else { -#if CYTHON_USE_PYLONG_INTERNALS - const digit* digits = ((PyLongObject*)x)->ob_digit; - switch (Py_SIZE(x)) { - case 0: return (long) 0; - case -1: __PYX_VERIFY_RETURN_INT(long, sdigit, -(sdigit) digits[0]) - case 1: __PYX_VERIFY_RETURN_INT(long, digit, +digits[0]) - case -2: - if (8 * sizeof(long) - 1 > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { - return (long) (((long)-1)*(((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case 2: - if (8 * sizeof(long) > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { - return (long) ((((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case -3: - if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { - return (long) (((long)-1)*(((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case 3: - if (8 * sizeof(long) > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { - return (long) ((((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case -4: - if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { - return (long) (((long)-1)*(((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case 4: - if (8 * sizeof(long) > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { - return (long) ((((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - } -#endif - if (sizeof(long) <= sizeof(long)) { - __PYX_VERIFY_RETURN_INT_EXC(long, long, PyLong_AsLong(x)) - } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { - __PYX_VERIFY_RETURN_INT_EXC(long, PY_LONG_LONG, PyLong_AsLongLong(x)) - } - } - { -#if CYTHON_COMPILING_IN_PYPY && !defined(_PyLong_AsByteArray) - PyErr_SetString(PyExc_RuntimeError, - "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); -#else - long val; - PyObject *v = __Pyx_PyNumber_Int(x); - #if PY_MAJOR_VERSION < 3 - if (likely(v) && !PyLong_Check(v)) { - PyObject *tmp = v; - v = PyNumber_Long(tmp); - Py_DECREF(tmp); - } - #endif - if (likely(v)) { - int one = 1; int is_little = (int)*(unsigned char *)&one; - unsigned char *bytes = (unsigned char *)&val; - int ret = _PyLong_AsByteArray((PyLongObject *)v, - bytes, sizeof(val), - is_little, !is_unsigned); - Py_DECREF(v); - if (likely(!ret)) - return val; - } -#endif - return (long) -1; - } - } else { - long val; - PyObject *tmp = __Pyx_PyNumber_Int(x); - if (!tmp) return (long) -1; - val = __Pyx_PyInt_As_long(tmp); - Py_DECREF(tmp); - return val; - } -raise_overflow: - PyErr_SetString(PyExc_OverflowError, - "value too large to convert to long"); - return (long) -1; -raise_neg_overflow: - PyErr_SetString(PyExc_OverflowError, - "can't convert negative value to long"); - return (long) -1; -} - -static int __Pyx_check_binary_version(void) { - char ctversion[4], rtversion[4]; - PyOS_snprintf(ctversion, 4, "%d.%d", PY_MAJOR_VERSION, PY_MINOR_VERSION); - PyOS_snprintf(rtversion, 4, "%s", Py_GetVersion()); - if (ctversion[0] != rtversion[0] || ctversion[2] != rtversion[2]) { - char message[200]; - PyOS_snprintf(message, sizeof(message), - "compiletime version %s of module '%.100s' " - "does not match runtime version %s", - ctversion, __Pyx_MODULE_NAME, rtversion); - return PyErr_WarnEx(NULL, message, 1); - } - return 0; -} - -static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) { - while (t->p) { - #if PY_MAJOR_VERSION < 3 - if (t->is_unicode) { - *t->p = PyUnicode_DecodeUTF8(t->s, t->n - 1, NULL); - } else if (t->intern) { - *t->p = PyString_InternFromString(t->s); - } else { - *t->p = PyString_FromStringAndSize(t->s, t->n - 1); - } - #else - if (t->is_unicode | t->is_str) { - if (t->intern) { - *t->p = PyUnicode_InternFromString(t->s); - } else if (t->encoding) { - *t->p = PyUnicode_Decode(t->s, t->n - 1, t->encoding, NULL); - } else { - *t->p = PyUnicode_FromStringAndSize(t->s, t->n - 1); - } - } else { - *t->p = PyBytes_FromStringAndSize(t->s, t->n - 1); - } - #endif - if (!*t->p) - return -1; - ++t; - } - return 0; -} - -static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char* c_str) { - return __Pyx_PyUnicode_FromStringAndSize(c_str, (Py_ssize_t)strlen(c_str)); -} -static CYTHON_INLINE char* __Pyx_PyObject_AsString(PyObject* o) { - Py_ssize_t ignore; - return __Pyx_PyObject_AsStringAndSize(o, &ignore); -} -static CYTHON_INLINE char* __Pyx_PyObject_AsStringAndSize(PyObject* o, Py_ssize_t *length) { -#if CYTHON_COMPILING_IN_CPYTHON && (__PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT) - if ( -#if PY_MAJOR_VERSION < 3 && __PYX_DEFAULT_STRING_ENCODING_IS_ASCII - __Pyx_sys_getdefaultencoding_not_ascii && -#endif - PyUnicode_Check(o)) { -#if PY_VERSION_HEX < 0x03030000 - char* defenc_c; - PyObject* defenc = _PyUnicode_AsDefaultEncodedString(o, NULL); - if (!defenc) return NULL; - defenc_c = PyBytes_AS_STRING(defenc); -#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII - { - char* end = defenc_c + PyBytes_GET_SIZE(defenc); - char* c; - for (c = defenc_c; c < end; c++) { - if ((unsigned char) (*c) >= 128) { - PyUnicode_AsASCIIString(o); - return NULL; - } - } - } -#endif - *length = PyBytes_GET_SIZE(defenc); - return defenc_c; -#else - if (__Pyx_PyUnicode_READY(o) == -1) return NULL; -#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII - if (PyUnicode_IS_ASCII(o)) { - *length = PyUnicode_GET_LENGTH(o); - return PyUnicode_AsUTF8(o); - } else { - PyUnicode_AsASCIIString(o); - return NULL; - } -#else - return PyUnicode_AsUTF8AndSize(o, length); -#endif -#endif - } else -#endif -#if (!CYTHON_COMPILING_IN_PYPY) || (defined(PyByteArray_AS_STRING) && defined(PyByteArray_GET_SIZE)) - if (PyByteArray_Check(o)) { - *length = PyByteArray_GET_SIZE(o); - return PyByteArray_AS_STRING(o); - } else -#endif - { - char* result; - int r = PyBytes_AsStringAndSize(o, &result, length); - if (unlikely(r < 0)) { - return NULL; - } else { - return result; - } - } -} -static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject* x) { - int is_true = x == Py_True; - if (is_true | (x == Py_False) | (x == Py_None)) return is_true; - else return PyObject_IsTrue(x); -} -static CYTHON_INLINE PyObject* __Pyx_PyNumber_Int(PyObject* x) { - PyNumberMethods *m; - const char *name = NULL; - PyObject *res = NULL; -#if PY_MAJOR_VERSION < 3 - if (PyInt_Check(x) || PyLong_Check(x)) -#else - if (PyLong_Check(x)) -#endif - return __Pyx_NewRef(x); - m = Py_TYPE(x)->tp_as_number; -#if PY_MAJOR_VERSION < 3 - if (m && m->nb_int) { - name = "int"; - res = PyNumber_Int(x); - } - else if (m && m->nb_long) { - name = "long"; - res = PyNumber_Long(x); - } -#else - if (m && m->nb_int) { - name = "int"; - res = PyNumber_Long(x); - } -#endif - if (res) { -#if PY_MAJOR_VERSION < 3 - if (!PyInt_Check(res) && !PyLong_Check(res)) { -#else - if (!PyLong_Check(res)) { -#endif - PyErr_Format(PyExc_TypeError, - "__%.4s__ returned non-%.4s (type %.200s)", - name, name, Py_TYPE(res)->tp_name); - Py_DECREF(res); - return NULL; - } - } - else if (!PyErr_Occurred()) { - PyErr_SetString(PyExc_TypeError, - "an integer is required"); - } - return res; -} -static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { - Py_ssize_t ival; - PyObject *x; -#if PY_MAJOR_VERSION < 3 - if (likely(PyInt_CheckExact(b))) { - if (sizeof(Py_ssize_t) >= sizeof(long)) - return PyInt_AS_LONG(b); - else - return PyInt_AsSsize_t(x); - } -#endif - if (likely(PyLong_CheckExact(b))) { - #if CYTHON_USE_PYLONG_INTERNALS - const digit* digits = ((PyLongObject*)b)->ob_digit; - const Py_ssize_t size = Py_SIZE(b); - if (likely(__Pyx_sst_abs(size) <= 1)) { - ival = likely(size) ? digits[0] : 0; - if (size == -1) ival = -ival; - return ival; - } else { - switch (size) { - case 2: - if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) { - return (Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); - } - break; - case -2: - if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) { - return -(Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); - } - break; - case 3: - if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) { - return (Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); - } - break; - case -3: - if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) { - return -(Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); - } - break; - case 4: - if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) { - return (Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); - } - break; - case -4: - if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) { - return -(Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); - } - break; - } - } - #endif - return PyLong_AsSsize_t(b); - } - x = PyNumber_Index(b); - if (!x) return -1; - ival = PyInt_AsSsize_t(x); - Py_DECREF(x); - return ival; -} -static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t ival) { - return PyInt_FromSize_t(ival); -} - - -#endif /* Py_PYTHON_H */ diff --git a/src/demo/worker/benchmark.hpp b/src/demo/worker/benchmark.hpp deleted file mode 100644 index f92343830..000000000 --- a/src/demo/worker/benchmark.hpp +++ /dev/null @@ -1,110 +0,0 @@ -#pragma once - -#include <vector> -#include <memory> -#include <chrono> -#include <future> - -#include "debug/log.hpp" -#include "worker.hpp" - -template <class W> -class WorkerRunner -{ -public: - WorkerRunner(const std::string& query) - : worker(std::make_unique<W>(query)) {} - - W* operator->() { return worker.get(); } - const W* operator->() const { return worker.get(); } - - void operator()(std::chrono::duration<double> duration) - { - std::packaged_task<WorkerResult()> task([this, duration]() { - return this->worker->benchmark(duration); - }); - - result = std::move(task.get_future()); - std::thread(std::move(task)).detach(); - } - - std::unique_ptr<W> worker; - std::future<WorkerResult> result; -}; - -struct Result -{ - std::chrono::duration<double> elapsed; - std::vector<uint64_t> requests; -}; - -Result benchmark(const std::string& host, - const std::string& port, - int connections_per_query, // duplicate workers for a query - double duration, // in seconds - const std::vector<std::string>& queries) -{ - auto threads = queries.size(); - - std::vector<WorkerRunner<CypherWorker>> workers; - - for(size_t i = 0; i < threads; ++i) - workers.emplace_back(queries[i]); - - for(size_t i = 0; i < threads * connections_per_query; ++i) - workers[i % threads]->connect(host, port); - - for(auto& worker : workers) - worker(std::chrono::duration<double>(duration)); - - std::vector<WorkerResult> results; - - for(auto& worker : workers) - { - worker.result.wait(); - results.push_back(worker.result.get()); - } - - auto start = std::min_element(results.begin(), results.end(), - [](auto a, auto b) { return a.start < b.start; })->start; - - auto end = std::max_element(results.begin(), results.end(), - [](auto a, auto b) { return a.end < b.end; })->end; - - std::vector<uint64_t> qps; - - for(auto& result : results) - qps.push_back(result.requests); - - return {end - start, qps}; -} - -std::string benchmark_json(const std::string& host, - const std::string& port, - int connections, - double duration, - const std::vector<std::string>& queries) -{ - auto result = benchmark(host, port, connections, duration, queries); - - auto& reqs = result.requests; - auto elapsed = result.elapsed.count(); - - auto total = std::accumulate(reqs.begin(), reqs.end(), 0.0, - [](auto acc, auto x) { return acc + x; } - ); - - auto created_count = counter.load(); - - std::string json = "{\"total\":" + std::to_string(total / elapsed) + "," - + " \"per_query\": ["; - for(size_t i = 0; i < queries.size(); ++i) { - if (i == 0) { - json += std::to_string(reqs[i] / elapsed); - continue; - } - json += ", " + std::to_string(reqs[i] / elapsed); - } - json += "], \"counter\": " + std::to_string(created_count) + " }"; - return json; -} diff --git a/src/demo/worker/benchmark.pyx b/src/demo/worker/benchmark.pyx deleted file mode 100644 index eedbfe83b..000000000 --- a/src/demo/worker/benchmark.pyx +++ /dev/null @@ -1,20 +0,0 @@ -# -*- coding: utf-8 -*- - -from libcpp.string cimport string -from libcpp.vector cimport vector - -cdef extern from "benchmark.hpp" nogil: - string benchmark_json(const string& host, - const string& port, - int connections_per_query, - double duration, - const vector[string]& queries) - - -def benchmark(host, port, connections_per_query, duration, queries): - ''' - ''' - result = benchmark_json(<const string&> host, <const string&> port, - <int> connections_per_query, <double> duration, - <const vector[string]&> queries) - return result diff --git a/src/demo/worker/benchmark_json.cpp b/src/demo/worker/benchmark_json.cpp deleted file mode 100644 index f40ec5dc8..000000000 --- a/src/demo/worker/benchmark_json.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "benchmark.hpp" - -int main(int argc, char* argv[]) -{ - if (argc < 6) - std::exit(EXIT_FAILURE); - - // read arguments - auto host = std::string(argv[1]); - auto port = std::string(argv[2]); - auto connections = std::stoi(argv[3]); - auto duration = std::stod(argv[4]); - auto count = std::stoi(argv[5]); - - counter.store(count); - - std::vector<std::string> queries; - for (int i = 6; i < argc; ++i) { - queries.emplace_back(std::string(argv[i])); - } - - // print result - std::cout << benchmark_json(host, port, connections, duration, queries); - - return 0; -} diff --git a/src/demo/worker/client.cpp b/src/demo/worker/client.cpp deleted file mode 100644 index 9480dc3d0..000000000 --- a/src/demo/worker/client.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include <iostream> -#include <cstdlib> -#include <vector> - -#include "debug/log.hpp" -#include "benchmark.hpp" - -void help() -{ - std::cout << "error: too few arguments." << std::endl - << "usage: host port connections_per_query duration[s]" - << std::endl; - - std::exit(0); -} - -int main(int argc, char* argv[]) -{ - if(argc < 5) - help(); - - auto host = std::string(argv[1]); - auto port = std::string(argv[2]); - auto connections = std::stoi(argv[3]); - auto duration = std::stod(argv[4]); - - // neo4j - std::vector<std::string> queries { - "CREATE (n:Item{id:@}) RETURN n", - "MATCH (n:Item{id:#}),(m:Item{id:#}) CREATE (n)-[r:test]->(m) RETURN r", - "MATCH (n:Item{id:#}) SET n.prop = # RETURN n", - "MATCH (n:Item{id:#}) RETURN n", - "MATCH (n:Item{id:#})-[r]->(m) RETURN count(r)" - }; - - auto threads = queries.size(); - - std::cout << "Running " << queries.size() << " queries each on " - << connections << " connections " - << "using a total of " << connections * threads << " connections " - << "for " << duration << " seconds." << std::endl - << "..." << std::endl; - - auto result = benchmark(host, port, connections, duration, queries); - - auto& reqs = result.requests; - auto elapsed = result.elapsed.count(); - - auto total = std::accumulate(reqs.begin(), reqs.end(), 0.0, - [](auto acc, auto x) { return acc + x; } - ); - - std::cout << "Total of " << total << " requests in " - << elapsed << "s (" << int(total / elapsed) << " req/s)." - << std::endl; - - for(size_t i = 0; i < queries.size(); ++i) - std::cout << queries[i] << " => " - << int(reqs[i] / elapsed) << " req/s." << std::endl; - - return 0; -} diff --git a/src/demo/worker/client.py b/src/demo/worker/client.py deleted file mode 100644 index 477bd1613..000000000 --- a/src/demo/worker/client.py +++ /dev/null @@ -1,65 +0,0 @@ -# -*- coding: utf-8 -*- - -from os import path -from json import loads -from subprocess import check_output - -from .benchmark import benchmark - - -def subprocess_client(args): - ''' - Runs the client in a separate process. - - :param args: list of strings, process arguments (the first element is - path to the exe) - ''' - result = check_output(args) - return loads(result.decode('utf-8')) - - -def wrapped_client(*args): - ''' - Runs the client via the python module which was built using cython. - - :param args: [str], list of ctypes objects - the interface is specified inside the benchmark.pyx - Mapping: - b'string' -> string - [b'string',...] -> vector<string> - ''' - result = benchmark(*args) - return loads(result.decode('utf-8')) - - -def main_subprocess(): - ''' - Example of subprocess call. - ''' - exe = path.join(path.dirname(path.abspath(__file__)), "benchmark_json.out") - args = ["localhost", "7474", "16", "1", - "CREATE (n{id:@}) RETURN n", "CREATE (n{id:@}) RETURN n"] - result = subprocess_client([exe] + args) - return result - - -def main_wrapped(): - ''' - Example of cython call. - ''' - args = [b"localhost", b"7474", 1, 1, - [b"CREATE (n{id:@}) RETURN n", b"CREATE (n{id:@}) RETURN n"]] - result = wrapped_client(*args) - return result - - -def main(): - ''' - ''' - print("Subprocess:") - print(main_subprocess()) - print("Wrapped:") - print(main_wrapped()) - -if __name__ == '__main__': - main() diff --git a/src/demo/worker/compile_client.sh b/src/demo/worker/compile_client.sh deleted file mode 100755 index a10ce6228..000000000 --- a/src/demo/worker/compile_client.sh +++ /dev/null @@ -1,2 +0,0 @@ -clang++ -O2 -DNDEBUG -std=c++14 client.cpp -o client.out -I../../ -pthread -clang++ -O2 -DNDEBUG -std=c++14 benchmark_json.cpp -o benchmark_json.out -I../../ -pthread diff --git a/src/demo/worker/cypher.hpp b/src/demo/worker/cypher.hpp deleted file mode 100644 index 6e883d479..000000000 --- a/src/demo/worker/cypher.hpp +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once - -#include <string> - -#include "memory/literals.hpp" -#include "cypher_replacer.hpp" - -using namespace memory::literals; - -class Cypher -{ - static std::string body_start; - static std::string body_end; - -public: - Cypher() - { - request.reserve(64_kB); - } - - std::string& operator()(std::string query) - { - request.clear(); - replacer(query); - - // request begin and headers - request += "POST /db/data/transaction/commit HTTP/1.1\r\n" \ - "Host: localhost:7474\r\n" \ - "Authorization: Basic bmVvNGo6cGFzcw==\r\n" \ - "Accept: application/json; charset=UTF-8\r\n" \ - "Content-Type: application/json\r\n" \ - "Content-Length: "; - - // content length - auto size = body_start.size() + query.size() + body_end.size(); - request += std::to_string(size); - - // headers end - request += "\r\n\r\n"; - - // write body - request += body_start; - request += query; - request += body_end; - - return request; - } - -private: - std::string request; - CypherReplacer replacer; -}; - -std::string Cypher::body_start = "{\"statements\":[{\"statement\":\""; -std::string Cypher::body_end = "\"}]}"; diff --git a/src/demo/worker/cypher_replacer.hpp b/src/demo/worker/cypher_replacer.hpp deleted file mode 100644 index 210c1898b..000000000 --- a/src/demo/worker/cypher_replacer.hpp +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include <random> -#include <atomic> - -#include "replacer.hpp" -#include "random.hpp" - -static std::atomic<uint64_t> counter {0}; -static thread_local std::mt19937 mt; - -class CypherReplacer -{ - std::uniform_int_distribution<uint64_t> random_int; - RandomString random_string; - -public: - CypherReplacer() - { - replacer - .replace("#", [&]() { - return std::to_string(random_int(mt) % (counter.load() + 1)); - }) - .replace("^", [&]() { - return random_string(mt, 15); - }) - .replace("@", [&]() { - return std::to_string(counter.fetch_add(1)); - }); - } - - std::string& operator()(std::string& query) - { - return replacer(query); - } - -private: - Replacer replacer; -}; diff --git a/src/demo/worker/random.hpp b/src/demo/worker/random.hpp deleted file mode 100644 index 22999f0b9..000000000 --- a/src/demo/worker/random.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include <string> -#include <random> - -class RandomString -{ - static constexpr char charset[] = - "0123456789" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz"; - -public: - template <class Rg> - std::string operator()(Rg&& gen, size_t len) - { - auto str = std::string(); - - while(str.size() < len) - str.push_back(charset[rnd(std::forward<Rg>(gen))]); - - return str; - } - -private: - std::uniform_int_distribution<> rnd {0, sizeof(charset) - 1}; -}; - -constexpr char RandomString::charset[]; diff --git a/src/demo/worker/replacer.hpp b/src/demo/worker/replacer.hpp deleted file mode 100644 index cdbea2842..000000000 --- a/src/demo/worker/replacer.hpp +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - -#include <vector> -#include <string> -#include <functional> - -class Replacer -{ - struct Rule - { - std::string match; - std::function<std::string()> generator; - }; - -public: - Replacer() {} - - template <class F> - Replacer& replace(const std::string& match, F&& generator) - { - rules.push_back({match, std::forward<F>(generator)}); - return *this; - } - - std::string& operator()(std::string& str) - { - size_t n; - - for(auto& rule : rules) - { - while((n = str.find_first_of(rule.match)) != std::string::npos) - str.replace(n, rule.match.size(), rule.generator()); - } - - return str; - } - -private: - std::vector<Rule> rules; -}; diff --git a/src/demo/worker/setup.py b/src/demo/worker/setup.py deleted file mode 100644 index 0827f9a3c..000000000 --- a/src/demo/worker/setup.py +++ /dev/null @@ -1,17 +0,0 @@ -# -*- coding: utf-8 -*- - -from distutils.core import setup, Extension -from Cython.Distutils import build_ext - -setup( - name='Benchmark client', - ext_modules=[ - Extension( - name='benchmark', - sources=['benchmark.pyx'], - extra_compile_args=['-O2', '-std=c++14'], - include_dirs=["../../"], - language='c++') - ], - cmdclass={'build_ext': build_ext} -) diff --git a/src/demo/worker/setup_runner.sh b/src/demo/worker/setup_runner.sh deleted file mode 100755 index 149ae89a1..000000000 --- a/src/demo/worker/setup_runner.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -python setup.py build_ext --inplace -# mv benchmark.cpp __benchmark__.cpp diff --git a/src/demo/worker/simple_client.hpp b/src/demo/worker/simple_client.hpp deleted file mode 100644 index 7459124d4..000000000 --- a/src/demo/worker/simple_client.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include "io/network/client.hpp" - -template <class Derived, class Stream> -class SimpleClient : public io::Client<Derived, Stream> -{ - char buf[65535]; - -public: - using Buffer = typename io::StreamReader<Derived, Stream>::Buffer; - - void on_wait_timeout() {} - - void on_error(Stream&) - { - std::abort(); - } - - Buffer on_alloc(Stream&) - { - return Buffer { buf, sizeof buf }; - } - - void on_close(Stream&) {} -}; diff --git a/src/demo/worker/worker.hpp b/src/demo/worker/worker.hpp deleted file mode 100644 index a51c59b72..000000000 --- a/src/demo/worker/worker.hpp +++ /dev/null @@ -1,83 +0,0 @@ -#pragma once - -#include <functional> -#include <algorithm> -#include <iostream> -#include <random> -#include <vector> -#include <thread> -#include <chrono> -#include <atomic> -#include <future> - -#include "simple_client.hpp" - -#include "io/network/tcp/stream.hpp" -#include "cypher.hpp" - -struct WorkerResult -{ - std::chrono::high_resolution_clock::time_point start, end; - uint64_t requests; -}; - -class CypherWorker : public SimpleClient<CypherWorker, io::tcp::Stream> -{ -public: - CypherWorker(const std::string& query) - : query(query), requests(0) {} - - io::tcp::Stream& on_connect(io::Socket&& socket) - { - streams.emplace_back(std::make_unique<io::tcp::Stream>( - std::forward<io::Socket>(socket) - )); - - return *streams.back(); - } - - void on_read(io::tcp::Stream& stream, Buffer& buf) - { - /* std::cout << "------------------- RESPONSE ------------------" << std::endl; */ - /* std::cout << std::string(buf.ptr, buf.len) << std::endl; */ - /* std::cout << "-----------------------------------------------" << std::endl; */ - - requests++; - send(stream.socket); - } - - void send(io::Socket& socket) - { - // cypherize and send the request - //socket.write(cypher(queries[idx])); - auto req = cypher(query); - socket.write(req); - } - - WorkerResult benchmark(std::chrono::duration<double> duration) - { - using clock = std::chrono::high_resolution_clock; - clock::time_point end, start = clock::now(); - - for(auto& stream : streams) - send(stream->socket); - - while(true) - { - this->wait_and_process_events(); - - if((end = clock::now()) - start > duration) - break; - } - - return {start, end, requests}; - } - -private: - std::uniform_int_distribution<> random_int; - Cypher cypher; - - std::vector<std::unique_ptr<io::tcp::Stream>> streams; - std::string query; - uint64_t requests; -}; diff --git a/src/demo/worker/worker_web_service.py b/src/demo/worker/worker_web_service.py deleted file mode 100644 index 35264cfa6..000000000 --- a/src/demo/worker/worker_web_service.py +++ /dev/null @@ -1,138 +0,0 @@ -# -*- coding: utf-8 -*- - -import logging -import threading -from os import path -from flask import request, jsonify - -from web_service import WebService -# from .client import wrapped_client -from .client import subprocess_client - -log = logging.getLogger(__name__) - - -class WorkerWebService(WebService): - ''' - Memgraph worker web server. For now it wraps the flask server. - ''' - - def __init__(self): - ''' - Instantiates the flask web server. - ''' - super().__init__(__name__) - self.params_data = {} - self.is_simulation_running = False - self.stats_data = None - self.setup_routes() - self.counter = None - - def setup_routes(self): - ''' - Setup all routes. - ''' - super().setup_routes() - self.add_route('/', self.index, 'GET') - self.add_route('/<path:path>', self.static, 'GET') - self.add_route('/start', self.start, 'POST') - self.add_route('/stop', self.stop, 'POST') - self.add_route('/stats', self.stats, 'GET') - self.add_route('/params', self.params_get, 'GET') - self.add_route('/params', self.params_set, 'POST') - - def index(self): - ''' - Serves demo.html on the index path. - ''' - print('index') - return self.server.send_static_file('demo.html') - - def static(self, path): - ''' - Serves other static files. - ''' - return self.server.send_static_file(path) - - def run_simulation(self): - ''' - If flag is_simulation_running flag is up (True) the executor - epoch will be executed. Epochs will be executed until somebody - set is_simulation_running flag to Flase. - ''' - log.info('new simulation run') - - while self.is_simulation_running: - # cython call TODO relase the GIL - # params = [ - # self.params_data['host'].encode('utf-8'), - # self.params_data['port'].encode('utf-8'), - # self.params_data['connections'], - # self.params_data['duration'], - # list(map(lambda x: x.encode('utf-8'), - # self.params_data['queries'])) - # ] - # data = wrapped_client(*params) - - # subprocess call - if not self.counter: - self.counter = 0 - params = [ - str(self.params_data['host']), - str(self.params_data['port']), - str(self.params_data['connections']), - str(self.params_data['duration']), - str(self.counter) - ] + list(map(lambda x: str(x), self.params_data['queries'])) - exe = path.join(path.dirname(path.abspath(__file__)), - "benchmark_json.out") - self.stats_data = subprocess_client([exe] + params) - self.counter = self.stats_data['counter'] - - def start(self): - ''' - Starts run in a separate thread. - ''' - self.counter = 0 - self.is_simulation_running = True - t = threading.Thread(target=self.run_simulation, daemon=True) - t.start() - return ('', 204) - - def stop(self): - ''' - Stops the worker run. - ''' - self.params_data = {} - self.stats_data = None - self.is_simulation_running = False - return ('', 204) - - def stats(self): - ''' - Returns the worker stats. Queries per second. - ''' - if not self.stats_data: - return ('', 204) - - return jsonify(self.stats_data) - - def params_get(self): - ''' - Returns worker parameters. - ''' - return jsonify(self.params_data) - - def params_set(self): - ''' - Sets worker parameters. - ''' - data = request.get_json() - - param_names = ['host', 'port', 'connections', 'duration', 'queries'] - - for param in param_names: - if param in data: - self.params_data[param] = data[param] - - return self.params_get() diff --git a/src/demo/worker_web_service_init.py b/src/demo/worker_web_service_init.py deleted file mode 100644 index 1804de575..000000000 --- a/src/demo/worker_web_service_init.py +++ /dev/null @@ -1,20 +0,0 @@ -# -*- coding: utf-8 -*- - -import logging - -from config import config -from worker.worker_web_service import WorkerWebService - - -def _init(): - ''' - Defines log level. - ''' - logging.basicConfig(level=config.log_level) - - return WorkerWebService().server - -app = _init() - -if __name__ == '__main__': - app.run(host=config.host, port=config.port) diff --git a/src/examples/record_proxy.cpp b/src/examples/record_proxy.cpp deleted file mode 100644 index 4915ee853..000000000 --- a/src/examples/record_proxy.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include <iostream> - -#include "storage/vertex_proxy.hpp" - -using std::cout; -using std::endl; - -int main() { - VertexProxy vertex_proxy; - cout << "Record Proxy Examples" << endl; - return 0; -} diff --git a/src/examples/test.cpp b/src/examples/test.cpp deleted file mode 100644 index 1bcf3c612..000000000 --- a/src/examples/test.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include <iostream> - -class A -{ -public: - class B; - -}; - -class A::B -{ -public: - -}; - -int main(void) -{ - A a; - A::B b; - - - - return 0; -} diff --git a/src/experimental/cache_benchmark.cpp b/src/experimental/cache_benchmark.cpp deleted file mode 100644 index ed5e132f0..000000000 --- a/src/experimental/cache_benchmark.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include <iostream> - -#include "utils/time/timer.hpp" - -using std::cout; -using std::endl; - -using ns = std::chrono::nanoseconds; -using ms = std::chrono::milliseconds; - -constexpr long iterations_no = 10 * 1024 * 1024; - -struct DataShort -{ - long a; - long b; -}; - -struct DataLong -{ - long a; - long b; - long c; - long d; -}; - -DataShort *data_short = new DataShort[iterations_no]; -DataLong *data_long = new DataLong[iterations_no]; - -int main() -{ - auto time_short = timer<ms>([]() { - for (long i = 0; i < iterations_no; i++) { - data_short[i].a = data_short[i].b; - } - }); - - auto time_long = timer<ms>([]() { - for (long i = 0; i < iterations_no; i++) { - data_long[i].a = data_long[i].b; - } - }); - - cout << "Time short: " << time_short << " ms"<< endl; - cout << "Time long: " << time_long << " ms" << endl; - - return 0; -} diff --git a/src/experimental/cache_benchmark.run b/src/experimental/cache_benchmark.run deleted file mode 100755 index b2b470c00..000000000 Binary files a/src/experimental/cache_benchmark.run and /dev/null differ diff --git a/src/io/network/test.cpp b/src/io/network/test.cpp index f79be771a..a69ab52a8 100644 --- a/src/io/network/test.cpp +++ b/src/io/network/test.cpp @@ -1,15 +1,19 @@ #include <iostream> -#include <vector> -#include <thread> #include <signal.h> - -#include "debug/log.hpp" +#include <thread> +#include <vector> #include "http/request.hpp" #include "http/response.hpp" -#include "socket.hpp" #include "http/worker.hpp" +#include "socket.hpp" + +#ifndef NDEBUG +#define LOG_DEBUG(x) std::cout << x << std::endl; +#else +#define LOG_DEBUG(x) +#endif std::hash<std::thread::id> hash; @@ -18,12 +22,9 @@ constexpr unsigned K = 128; std::array<http::Parser<http::Request, http::Response>, K> workers; std::array<std::thread, K> threads; -std::atomic<bool> alive { true }; +std::atomic<bool> alive{true}; -void exiting() -{ - LOG_DEBUG("Exiting..."); -} +void exiting() { LOG_DEBUG("Exiting..."); } void sigint_handler(int) { @@ -36,15 +37,15 @@ void sigint_handler(int) int main(void) { - //std::atexit(exiting); + // std::atexit(exiting); signal(SIGINT, sigint_handler); - for(size_t i = 0; i < workers.size(); ++i) + for (size_t i = 0; i < workers.size(); ++i) { - auto& w = workers[i]; + auto &w = workers[i]; threads[i] = std::thread([i, &w]() { - while(alive) + while (alive) { LOG_DEBUG("waiting for events on thread " << i); w.wait_and_process_events(); @@ -69,71 +70,70 @@ int main(void) socket.set_non_blocking(); socket.listen(1024); - int efd, s; - struct epoll_event event; - struct epoll_event *events; + int efd, s; + struct epoll_event event; + struct epoll_event *events; - efd = epoll_create1 (0); - if (efd == -1) + efd = epoll_create1(0); + if (efd == -1) { - perror ("epoll_create"); - abort (); + perror("epoll_create"); + abort(); } - event.data.fd = socket; - event.events = EPOLLIN | EPOLLET; - s = epoll_ctl (efd, EPOLL_CTL_ADD, socket, &event); - if (s == -1) + event.data.fd = socket; + event.events = EPOLLIN | EPOLLET; + s = epoll_ctl(efd, EPOLL_CTL_ADD, socket, &event); + if (s == -1) { - perror ("epoll_ctl"); - abort (); + perror("epoll_ctl"); + abort(); } - /* Buffer where events are returned */ - events = static_cast<struct epoll_event*>(calloc (MAXEVENTS, sizeof event)); + /* Buffer where events are returned */ + events = static_cast<struct epoll_event *>(calloc(MAXEVENTS, sizeof event)); - /* The event loop */ - while (1) + /* The event loop */ + while (1) { - int n, i; + int n, i; - LOG_DEBUG("acceptor waiting for events"); - n = epoll_wait (efd, events, MAXEVENTS, -1); + LOG_DEBUG("acceptor waiting for events"); + n = epoll_wait(efd, events, MAXEVENTS, -1); - LOG_DEBUG("acceptor recieved " << n << " connection requests"); + LOG_DEBUG("acceptor recieved " << n << " connection requests"); - for (i = 0; i < n; i++) - { - if ((events[i].events & EPOLLERR) || - (events[i].events & EPOLLHUP) || - (!(events[i].events & EPOLLIN))) - { - /* An error has occured on this fd, or the socket is not - ready for reading (why were we notified then?) */ - fprintf (stderr, "epoll error\n"); - close (events[i].data.fd); - continue; - } + for (i = 0; i < n; i++) + { + if ((events[i].events & EPOLLERR) || + (events[i].events & EPOLLHUP) || + (!(events[i].events & EPOLLIN))) + { + /* An error has occured on this fd, or the socket is not + ready for reading (why were we notified then?) */ + fprintf(stderr, "epoll error\n"); + close(events[i].data.fd); + continue; + } - else if (socket == events[i].data.fd) - { - /* We have a notification on the listening socket, which - means one or more incoming connections. */ - while (true) - { - LOG_DEBUG("trying to accept connection on thread " << idx); - if(!workers[idx].accept(socket)) - break; + else if (socket == events[i].data.fd) + { + /* We have a notification on the listening socket, which + means one or more incoming connections. */ + while (true) + { + LOG_DEBUG("trying to accept connection on thread " << idx); + if (!workers[idx].accept(socket)) break; - LOG_DEBUG("Accepted a new connection on thread " << idx); - idx = (idx + 1) % workers.size(); - break; - } + LOG_DEBUG("Accepted a new connection on thread " << idx); + idx = (idx + 1) % workers.size(); + break; + } } } } - free (events); + free(events); return 0; } diff --git a/src/query_engine/template/template_code_cpu.cpp b/src/query_engine/template/template_code_cpu_cpp similarity index 100% rename from src/query_engine/template/template_code_cpu.cpp rename to src/query_engine/template/template_code_cpu_cpp diff --git a/tests/unit/ptr_int.cpp b/tests/unit/ptr_int.cpp index a3589ae34..e59bbe80a 100644 --- a/tests/unit/ptr_int.cpp +++ b/tests/unit/ptr_int.cpp @@ -3,6 +3,11 @@ #include "data_structures/ptr_int.hpp" +TEST_CASE("Size of pointer integer object") +{ + REQUIRE(sizeof(PtrInt<int *, 1, int>) == sizeof(uintptr_t)); +} + TEST_CASE("Construct and read pointer integer pair type") { auto ptr1 = std::make_unique<int>(2); @@ -13,8 +18,8 @@ TEST_CASE("Construct and read pointer integer pair type") auto ptr2 = std::make_unique<int>(2); - PtrInt<int *, 3, int> pack2(ptr2.get(), 2); + PtrInt<int *, 3, int> pack2(ptr2.get(), 4); - REQUIRE(pack2.get_int() == 2); + REQUIRE(pack2.get_int() == 4); REQUIRE(pack2.get_ptr() == ptr2.get()); }