Commit 96b74bab274c9e6fefca0a57f7365789684b780a

Authored by Karpikau Andrei
1 parent b7aedd88

remove dummy app, add images

Showing 103 changed files with 6738 additions and 2277 deletions
1   -<?xml version="1.0" encoding="UTF-8"?>
2   -<Settings><!--This file was automatically generated by Ruby plugin.
3   -You are allowed to:
4   -1. Reorder generators
5   -2. Remove generators
6   -3. Add installed generators
7   -To add new installed generators automatically delete this file and reload the project.
8   ---><GeneratorsGroup><Generator name="active_record:devise" /><Generator name="assets" /><Generator name="controller" /><Generator name="delayed_job" /><Generator name="delayed_job:active_record" /><Generator name="delayed_job:upgrade" /><Generator name="devise" /><Generator name="devise:controllers" /><Generator name="devise:install" /><Generator name="devise:views" /><Generator name="factory_girl:model" /><Generator name="generator" /><Generator name="helper" /><Generator name="integration_test" /><Generator name="jbuilder" /><Generator name="job" /><Generator name="js:assets" /><Generator name="mailer" /><Generator name="migration" /><Generator name="model" /><Generator name="mongoid:devise" /><Generator name="resource" /><Generator name="responders:install" /><Generator name="responders_controller" /><Generator name="rspec:controller" /><Generator name="rspec:feature" /><Generator name="rspec:helper" /><Generator name="rspec:install" /><Generator name="rspec:integration" /><Generator name="rspec:job" /><Generator name="rspec:mailer" /><Generator name="rspec:model" /><Generator name="rspec:observer" /><Generator name="rspec:request" /><Generator name="rspec:scaffold" /><Generator name="rspec:view" /><Generator name="sass:assets" /><Generator name="scaffold" /><Generator name="scaffold_controller" /><Generator name="scss:assets" /><Generator name="task" /><Generator name="test_unit:generator" /><Generator name="test_unit:job" /><Generator name="test_unit:plugin" /></GeneratorsGroup></Settings>
1   -kanjai
\ No newline at end of file
1   -<?xml version="1.0" encoding="UTF-8"?>
2   -<Settings><!--This file was automatically generated by Ruby plugin.
3   -You are allowed to:
4   -1. Remove rake task
5   -2. Add existing rake tasks
6   -To add existing rake tasks automatically delete this file and reload the project.
7   ---><RakeGroup description="" fullCmd="" taksId="rake"><RakeGroup description="" fullCmd="" taksId="app"><RakeTask description="List versions of all Rails frameworks and the environment" fullCmd="app:about" taksId="about" /><RakeGroup description="" fullCmd="" taksId="assets"><RakeTask description="Remove old compiled assets" fullCmd="app:assets:clean[keep]" taksId="clean[keep]" /><RakeTask description="Remove compiled assets" fullCmd="app:assets:clobber" taksId="clobber" /><RakeTask description="Load asset compile environment" fullCmd="app:assets:environment" taksId="environment" /><RakeTask description="Compile all the assets named in config.assets.precompile" fullCmd="app:assets:precompile" taksId="precompile" /><RakeTask description="" fullCmd="app:assets:clean" taksId="clean" /></RakeGroup><RakeGroup description="" fullCmd="" taksId="cache_digests"><RakeTask description="Lookup first-level dependencies for TEMPLATE (like messages/show or comments/_comment.html)" fullCmd="app:cache_digests:dependencies" taksId="dependencies" /><RakeTask description="Lookup nested dependencies for TEMPLATE (like messages/show or comments/_comment.html)" fullCmd="app:cache_digests:nested_dependencies" taksId="nested_dependencies" /></RakeGroup><RakeGroup description="" fullCmd="" taksId="db"><RakeTask description="Creates the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:create:all to create all databases in the config)" fullCmd="app:db:create" taksId="create" /><RakeTask description="Drops the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:drop:all to drop all databases in the config)" fullCmd="app:db:drop" taksId="drop" /><RakeGroup description="" fullCmd="" taksId="fixtures"><RakeTask description="Load fixtures into the current environment's database" fullCmd="app:db:fixtures:load" taksId="load" /><RakeTask description="" fullCmd="app:db:fixtures:identify" taksId="identify" /></RakeGroup><RakeTask description="Migrate the database (options: VERSION=x, VERBOSE=false, SCOPE=blog)" fullCmd="app:db:migrate" taksId="migrate" /><RakeGroup description="" fullCmd="" taksId="migrate"><RakeTask description="Display status of migrations" fullCmd="app:db:migrate:status" taksId="status" /><RakeTask description="" fullCmd="app:db:migrate:down" taksId="down" /><RakeTask description="" fullCmd="app:db:migrate:redo" taksId="redo" /><RakeTask description="" fullCmd="app:db:migrate:reset" taksId="reset" /><RakeTask description="" fullCmd="app:db:migrate:up" taksId="up" /></RakeGroup><RakeTask description="Rolls the schema back to the previous version (specify steps w/ STEP=n)" fullCmd="app:db:rollback" taksId="rollback" /><RakeGroup description="" fullCmd="" taksId="schema"><RakeGroup description="" fullCmd="" taksId="cache"><RakeTask description="Clear a db/schema_cache.dump file" fullCmd="app:db:schema:cache:clear" taksId="clear" /><RakeTask description="Create a db/schema_cache.dump file" fullCmd="app:db:schema:cache:dump" taksId="dump" /></RakeGroup><RakeTask description="Create a db/schema.rb file that is portable against any DB supported by AR" fullCmd="app:db:schema:dump" taksId="dump" /><RakeTask description="Load a schema.rb file into the database" fullCmd="app:db:schema:load" taksId="load" /><RakeTask description="" fullCmd="app:db:schema:load_if_ruby" taksId="load_if_ruby" /></RakeGroup><RakeTask description="Load the seed data from db/seeds.rb" fullCmd="app:db:seed" taksId="seed" /><RakeTask description="Create the database, load the schema, and initialize with the seed data (use db:reset to also drop the database first)" fullCmd="app:db:setup" taksId="setup" /><RakeGroup description="" fullCmd="" taksId="structure"><RakeTask description="Dump the database structure to db/structure.sql" fullCmd="app:db:structure:dump" taksId="dump" /><RakeTask description="Recreate the databases from the structure.sql file" fullCmd="app:db:structure:load" taksId="load" /><RakeTask description="" fullCmd="app:db:structure:load_if_sql" taksId="load_if_sql" /></RakeGroup><RakeTask description="Retrieves the current schema version number" fullCmd="app:db:version" taksId="version" /><RakeTask description="" fullCmd="app:db:_dump" taksId="_dump" /><RakeTask description="" fullCmd="app:db:abort_if_pending_migrations" taksId="abort_if_pending_migrations" /><RakeTask description="" fullCmd="app:db:charset" taksId="charset" /><RakeTask description="" fullCmd="app:db:collation" taksId="collation" /><RakeGroup description="" fullCmd="" taksId="create"><RakeTask description="" fullCmd="app:db:create:all" taksId="all" /></RakeGroup><RakeGroup description="" fullCmd="" taksId="drop"><RakeTask description="" fullCmd="app:db:drop:all" taksId="all" /></RakeGroup><RakeTask description="" fullCmd="app:db:forward" taksId="forward" /><RakeTask description="" fullCmd="app:db:load_config" taksId="load_config" /><RakeTask description="" fullCmd="app:db:purge" taksId="purge" /><RakeGroup description="" fullCmd="" taksId="purge"><RakeTask description="" fullCmd="app:db:purge:all" taksId="all" /></RakeGroup><RakeTask description="" fullCmd="app:db:reset" taksId="reset" /><RakeGroup description="" fullCmd="" taksId="test"><RakeTask description="" fullCmd="app:db:test:clone" taksId="clone" /><RakeTask description="" fullCmd="app:db:test:clone_schema" taksId="clone_schema" /><RakeTask description="" fullCmd="app:db:test:clone_structure" taksId="clone_structure" /><RakeTask description="" fullCmd="app:db:test:deprecated" taksId="deprecated" /><RakeTask description="" fullCmd="app:db:test:load" taksId="load" /><RakeTask description="" fullCmd="app:db:test:load_schema" taksId="load_schema" /><RakeTask description="" fullCmd="app:db:test:load_structure" taksId="load_structure" /><RakeTask description="" fullCmd="app:db:test:prepare" taksId="prepare" /><RakeTask description="" fullCmd="app:db:test:purge" taksId="purge" /></RakeGroup></RakeGroup><RakeGroup description="" fullCmd="" taksId="doc"><RakeTask description="Generate docs for the app -- also available doc:rails, doc:guides (options: TEMPLATE=/rdoc-template.rb, TITLE=&quot;Custom Title&quot;)" fullCmd="app:doc:app" taksId="app" /><RakeTask description="" fullCmd="app:doc:clobber" taksId="clobber" /><RakeTask description="" fullCmd="app:doc:clobber_app" taksId="clobber_app" /><RakeTask description="" fullCmd="app:doc:clobber_rails" taksId="clobber_rails" /><RakeTask description="" fullCmd="app:doc:guides" taksId="guides" /><RakeTask description="" fullCmd="app:doc:rails" taksId="rails" /><RakeTask description="" fullCmd="app:doc:reapp" taksId="reapp" /><RakeTask description="" fullCmd="app:doc:rerails" taksId="rerails" /></RakeGroup><RakeGroup description="" fullCmd="" taksId="install"><RakeTask description="This task test soap" fullCmd="app:install:user" taksId="user" /><RakeTask description="" fullCmd="app:install:zip_example" taksId="zip_example" /></RakeGroup><RakeGroup description="" fullCmd="" taksId="jobs"><RakeTask description="Exit with error status if any jobs older than max_age seconds haven't been attempted yet" fullCmd="app:jobs:check[max_age]" taksId="check[max_age]" /><RakeTask description="Clear the delayed_job queue" fullCmd="app:jobs:clear" taksId="clear" /><RakeTask description="Start a delayed_job worker" fullCmd="app:jobs:work" taksId="work" /><RakeTask description="Start a delayed_job worker and exit when all available jobs are complete" fullCmd="app:jobs:workoff" taksId="workoff" /><RakeTask description="" fullCmd="app:jobs:check" taksId="check" /><RakeTask description="" fullCmd="app:jobs:environment_options" taksId="environment_options" /></RakeGroup><RakeGroup description="" fullCmd="" taksId="kanjai"><RakeGroup description="" fullCmd="" taksId="install"><RakeTask description="Copy migrations from kanjai to application" fullCmd="app:kanjai:install:migrations" taksId="migrations" /></RakeGroup></RakeGroup><RakeGroup description="" fullCmd="" taksId="log"><RakeTask description="Truncates all *.log files in log/ to zero bytes (specify which logs with LOGS=test,development)" fullCmd="app:log:clear" taksId="clear" /></RakeGroup><RakeTask description="Prints out your Rack middleware stack" fullCmd="app:middleware" taksId="middleware" /><RakeTask description="Enumerate all annotations (use notes:optimize, :fixme, :todo for focus)" fullCmd="app:notes" taksId="notes" /><RakeGroup description="" fullCmd="" taksId="notes"><RakeTask description="Enumerate a custom annotation, specify with ANNOTATION=CUSTOM" fullCmd="app:notes:custom" taksId="custom" /><RakeTask description="" fullCmd="app:notes:fixme" taksId="fixme" /><RakeTask description="" fullCmd="app:notes:optimize" taksId="optimize" /><RakeTask description="" fullCmd="app:notes:todo" taksId="todo" /></RakeGroup><RakeGroup description="" fullCmd="" taksId="rails"><RakeTask description="Applies the template supplied by LOCATION=(/path/to/template) or URL" fullCmd="app:rails:template" taksId="template" /><RakeTask description="Update configs and some other initially generated files (or use just update:configs or update:bin)" fullCmd="app:rails:update" taksId="update" /><RakeGroup description="" fullCmd="" taksId="templates"><RakeTask description="" fullCmd="app:rails:templates:copy" taksId="copy" /></RakeGroup><RakeGroup description="" fullCmd="" taksId="update"><RakeTask description="" fullCmd="app:rails:update:bin" taksId="bin" /><RakeTask description="" fullCmd="app:rails:update:configs" taksId="configs" /></RakeGroup></RakeGroup><RakeTask description="Print out all defined routes in match order, with names" fullCmd="app:routes" taksId="routes" /><RakeTask description="Generate a cryptographically secure secret key (this is typically used to generate a secret for cookie sessions)" fullCmd="app:secret" taksId="secret" /><RakeTask description="Runs all tests in test folder" fullCmd="app:test" taksId="test" /><RakeGroup description="" fullCmd="" taksId="test"><RakeTask description="Run tests quickly by merging all types and not resetting db" fullCmd="app:test:all" taksId="all" /><RakeGroup description="" fullCmd="" taksId="all"><RakeTask description="Run tests quickly, but also reset db" fullCmd="app:test:all:db" taksId="db" /></RakeGroup><RakeTask description="Run tests quickly, but also reset db" fullCmd="app:test:db" taksId="db" /><RakeTask description="" fullCmd="app:test:controllers" taksId="controllers" /><RakeTask description="" fullCmd="app:test:deprecate_all" taksId="deprecate_all" /><RakeTask description="" fullCmd="app:test:functionals" taksId="functionals" /><RakeTask description="" fullCmd="app:test:generators" taksId="generators" /><RakeTask description="" fullCmd="app:test:helpers" taksId="helpers" /><RakeTask description="" fullCmd="app:test:integration" taksId="integration" /><RakeTask description="" fullCmd="app:test:jobs" taksId="jobs" /><RakeTask description="" fullCmd="app:test:mailers" taksId="mailers" /><RakeTask description="" fullCmd="app:test:models" taksId="models" /><RakeTask description="" fullCmd="app:test:prepare" taksId="prepare" /><RakeTask description="" fullCmd="app:test:run" taksId="run" /><RakeTask description="" fullCmd="app:test:single" taksId="single" /><RakeTask description="" fullCmd="app:test:units" taksId="units" /></RakeGroup><RakeGroup description="" fullCmd="" taksId="time"><RakeGroup description="" fullCmd="" taksId="zones"><RakeTask description="Displays all time zones, also available: time:zones:us, time:zones:local -- filter with OFFSET parameter, e.g., OFFSET=-6" fullCmd="app:time:zones:all" taksId="all" /><RakeTask description="" fullCmd="app:time:zones:local" taksId="local" /><RakeTask description="" fullCmd="app:time:zones:us" taksId="us" /></RakeGroup></RakeGroup><RakeGroup description="" fullCmd="" taksId="tmp"><RakeTask description="Clear session, cache, and socket files from tmp/ (narrow w/ tmp:sessions:clear, tmp:cache:clear, tmp:sockets:clear)" fullCmd="app:tmp:clear" taksId="clear" /><RakeTask description="Creates tmp directories for sessions, cache, sockets, and pids" fullCmd="app:tmp:create" taksId="create" /><RakeGroup description="" fullCmd="" taksId="cache"><RakeTask description="" fullCmd="app:tmp:cache:clear" taksId="clear" /></RakeGroup><RakeGroup description="" fullCmd="" taksId="pids"><RakeTask description="" fullCmd="app:tmp:pids:clear" taksId="clear" /></RakeGroup><RakeGroup description="" fullCmd="" taksId="sessions"><RakeTask description="" fullCmd="app:tmp:sessions:clear" taksId="clear" /></RakeGroup><RakeGroup description="" fullCmd="" taksId="sockets"><RakeTask description="" fullCmd="app:tmp:sockets:clear" taksId="clear" /></RakeGroup></RakeGroup><RakeTask description="" fullCmd="app:default" taksId="default" /><RakeTask description="" fullCmd="app:environment" taksId="environment" /><RakeGroup description="" fullCmd="" taksId="railties"><RakeGroup description="" fullCmd="" taksId="install"><RakeTask description="" fullCmd="app:railties:install:migrations" taksId="migrations" /></RakeGroup></RakeGroup></RakeGroup><RakeTask description="Build kanjai-0.0.25.gem into the pkg directory" fullCmd="build" taksId="build" /><RakeTask description="Remove RDoc HTML files" fullCmd="clobber_rdoc" taksId="clobber_rdoc" /><RakeGroup description="" fullCmd="" taksId="db"><RakeTask description="Create the database from config/database.yml for the current Rails.env (use db:create:all to create all databases in the config)" fullCmd="db:create" taksId="create" /><RakeTask description="Drops the database for the current Rails.env (use db:drop:all to drop all databases)" fullCmd="db:drop" taksId="drop" /><RakeGroup description="" fullCmd="" taksId="fixtures"><RakeTask description="Load fixtures into the current environment's database" fullCmd="db:fixtures:load" taksId="load" /></RakeGroup><RakeTask description="Migrate the database (options: VERSION=x, VERBOSE=false)" fullCmd="db:migrate" taksId="migrate" /><RakeGroup description="" fullCmd="" taksId="migrate"><RakeTask description="Display status of migrations" fullCmd="db:migrate:status" taksId="status" /><RakeTask description="" fullCmd="db:migrate:down" taksId="down" /><RakeTask description="" fullCmd="db:migrate:redo" taksId="redo" /><RakeTask description="" fullCmd="db:migrate:reset" taksId="reset" /><RakeTask description="" fullCmd="db:migrate:up" taksId="up" /></RakeGroup><RakeTask description="Rolls the schema back to the previous version (specify steps w/ STEP=n)" fullCmd="db:rollback" taksId="rollback" /><RakeGroup description="" fullCmd="" taksId="schema"><RakeTask description="Create a db/schema.rb file that can be portably used against any DB supported by AR" fullCmd="db:schema:dump" taksId="dump" /><RakeTask description="Load a schema.rb file into the database" fullCmd="db:schema:load" taksId="load" /></RakeGroup><RakeTask description="Load the seed data from db/seeds.rb" fullCmd="db:seed" taksId="seed" /><RakeTask description="Create the database, load the schema, and initialize with the seed data (use db:reset to also drop the db first)" fullCmd="db:setup" taksId="setup" /><RakeGroup description="" fullCmd="" taksId="structure"><RakeTask description="Dump the database structure to an SQL file" fullCmd="db:structure:dump" taksId="dump" /></RakeGroup><RakeTask description="Retrieves the current schema version number" fullCmd="db:version" taksId="version" /><RakeGroup description="" fullCmd="" taksId="create"><RakeTask description="" fullCmd="db:create:all" taksId="all" /></RakeGroup><RakeGroup description="" fullCmd="" taksId="drop"><RakeTask description="" fullCmd="db:drop:all" taksId="all" /></RakeGroup><RakeTask description="" fullCmd="db:reset" taksId="reset" /></RakeGroup><RakeTask description="Build and install kanjai-0.0.25.gem into system gems" fullCmd="install" taksId="install" /><RakeTask description="Build RDoc HTML files" fullCmd="rdoc" taksId="rdoc" /><RakeTask description="Create tag v0.0.25 and build and push kanjai-0.0.25.gem to Rubygems" fullCmd="release" taksId="release" /><RakeTask description="Rebuild RDoc HTML files" fullCmd="rerdoc" taksId="rerdoc" /><RakeTask description="Report code statistics (KLOCs, etc) from the application or engine" fullCmd="stats" taksId="stats" /><RakeTask description="Run tests" fullCmd="test" taksId="test" /><RakeTask description="" fullCmd="clobber" taksId="clobber" /><RakeTask description="" fullCmd="default" taksId="default" /><RakeTask description="" fullCmd="doc" taksId="doc" /><RakeTask description="" fullCmd="doc/app" taksId="doc/app" /><RakeTask description="" fullCmd="doc/app/created.rid" taksId="doc/app/created.rid" /><RakeTask description="" fullCmd="environment" taksId="environment" /><RakeTask description="" fullCmd="html" taksId="html" /><RakeTask description="" fullCmd="html/created.rid" taksId="html/created.rid" /><RakeTask description="" fullCmd="load_app" taksId="load_app" /><RakeTask description="" fullCmd="rdoc/created.rid" taksId="rdoc/created.rid" /><RakeGroup description="" fullCmd="" taksId="release"><RakeTask description="" fullCmd="release:guard_clean" taksId="guard_clean" /><RakeTask description="" fullCmd="release:rubygem_push" taksId="rubygem_push" /><RakeTask description="" fullCmd="release:source_control_push" taksId="source_control_push" /></RakeGroup><RakeTask description="" fullCmd="tmp" taksId="tmp" /><RakeTask description="" fullCmd="tmp/cache" taksId="tmp/cache" /><RakeTask description="" fullCmd="tmp/cache/assets" taksId="tmp/cache/assets" /><RakeTask description="" fullCmd="tmp/cache/assets/development" taksId="tmp/cache/assets/development" /><RakeTask description="" fullCmd="tmp/cache/assets/production" taksId="tmp/cache/assets/production" /><RakeTask description="" fullCmd="tmp/cache/assets/test" taksId="tmp/cache/assets/test" /><RakeTask description="" fullCmd="tmp/pids" taksId="tmp/pids" /><RakeTask description="" fullCmd="tmp/sessions" taksId="tmp/sessions" /><RakeTask description="" fullCmd="tmp/sockets" taksId="tmp/sockets" /></RakeGroup></Settings>
1   -<?xml version="1.0" encoding="UTF-8"?>
2   -<project version="4">
3   - <component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" />
4   -</project>
\ No newline at end of file
1   -<component name="InspectionProjectProfileManager">
2   - <profile version="1.0" is_locked="false">
3   - <option name="myName" value="Project Default" />
4   - <inspection_tool class="Rubocop" enabled="false" level="WARNING" enabled_by_default="false" />
5   - </profile>
6   -</component>
\ No newline at end of file
1   -<?xml version="1.0" encoding="UTF-8"?>
2   -<module type="RUBY_MODULE" version="4">
3   - <component name="FacetManager">
4   - <facet type="RailsFacetType" name="Ruby on Rails">
5   - <configuration>
6   - <RAILS_FACET_CONFIG_ID NAME="RAILS_FACET_SUPPORT_REMOVED" VALUE="false" />
7   - <RAILS_FACET_CONFIG_ID NAME="RAILS_TESTS_SOURCES_PATCHED" VALUE="true" />
8   - <RAILS_FACET_CONFIG_ID NAME="RAILS_FACET_APPLICATION_ROOT" VALUE="$MODULE_DIR$" />
9   - </configuration>
10   - </facet>
11   - <facet type="gem" name="Ruby Gem">
12   - <configuration />
13   - </facet>
14   - </component>
15   - <component name="ModuleRunConfigurationManager">
16   - <shared>
17   - <configuration default="false" name="test: kanjai" type="RakeRunConfigurationType" factoryName="Rake">
18   - <module name="kanjai" />
19   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="RUBY_ARGS" VALUE="" />
20   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="WORK DIR" VALUE="$MODULE_DIR$" />
21   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="SHOULD_USE_SDK" VALUE="false" />
22   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="ALTERN_SDK_NAME" VALUE="" />
23   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="myPassParentEnvs" VALUE="true" />
24   - <envs>
25   - <env name="RAILS_ENV" value="test" />
26   - </envs>
27   - <EXTENSION ID="BundlerRunConfigurationExtension" bundleExecEnabled="false" />
28   - <EXTENSION ID="JRubyRunConfigurationExtension" NailgunExecEnabled="false" />
29   - <EXTENSION ID="RubyCoverageRunConfigurationExtension" track_test_folders="true" runner="rcov">
30   - <COVERAGE_PATTERN ENABLED="true">
31   - <PATTERN REGEXPS="/.rvm/" INCLUDED="false" />
32   - </COVERAGE_PATTERN>
33   - </EXTENSION>
34   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="RAKE_TASK_NAME" VALUE="test" />
35   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="RAKE_TASK_ARGS" VALUE="" />
36   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="RAKE_TASK_ATTACHED_TEST_FRAMEWORKS" VALUE=":test_unit " />
37   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="RAKE_TASK_OPTION_TRACE" VALUE="false" />
38   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="RAKE_TASK_OPTION_DRYRUN" VALUE="false" />
39   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="RAKE_TASK_OPTION_PREREQS" VALUE="false" />
40   - <method v="2" />
41   - </configuration>
42   - <configuration default="false" name="spec: kanjai" type="RakeRunConfigurationType" factoryName="Rake">
43   - <module name="kanjai" />
44   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="RUBY_ARGS" VALUE="" />
45   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="WORK DIR" VALUE="$MODULE_DIR$" />
46   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="SHOULD_USE_SDK" VALUE="false" />
47   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="ALTERN_SDK_NAME" VALUE="" />
48   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="myPassParentEnvs" VALUE="true" />
49   - <EXTENSION ID="BundlerRunConfigurationExtension" bundleExecEnabled="false" />
50   - <EXTENSION ID="JRubyRunConfigurationExtension" NailgunExecEnabled="false" />
51   - <EXTENSION ID="RubyCoverageRunConfigurationExtension" track_test_folders="true" runner="rcov">
52   - <COVERAGE_PATTERN ENABLED="true">
53   - <PATTERN REGEXPS="/.rvm/" INCLUDED="false" />
54   - </COVERAGE_PATTERN>
55   - </EXTENSION>
56   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="RAKE_TASK_NAME" VALUE="spec" />
57   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="RAKE_TASK_ARGS" VALUE="" />
58   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="RAKE_TASK_ATTACHED_TEST_FRAMEWORKS" VALUE=":rspec " />
59   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="RAKE_TASK_OPTION_TRACE" VALUE="false" />
60   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="RAKE_TASK_OPTION_DRYRUN" VALUE="false" />
61   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="RAKE_TASK_OPTION_PREREQS" VALUE="false" />
62   - <method v="2" />
63   - </configuration>
64   - <configuration default="false" name="Production: kanjai" type="RailsRunConfigurationType" factoryName="Rails">
65   - <predefined_log_file id="RUBY_RAILS_SERVER" enabled="true" />
66   - <module name="kanjai" />
67   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="RUBY_ARGS" VALUE="" />
68   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="WORK DIR" VALUE="$MODULE_DIR$" />
69   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="SHOULD_USE_SDK" VALUE="false" />
70   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="ALTERN_SDK_NAME" VALUE="" />
71   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="myPassParentEnvs" VALUE="true" />
72   - <EXTENSION ID="BundlerRunConfigurationExtension" bundleExecEnabled="false" />
73   - <EXTENSION ID="JRubyRunConfigurationExtension" NailgunExecEnabled="false" />
74   - <EXTENSION ID="RubyCoverageRunConfigurationExtension" track_test_folders="true" runner="rcov">
75   - <COVERAGE_PATTERN ENABLED="true">
76   - <PATTERN REGEXPS="/.rvm/" INCLUDED="false" />
77   - </COVERAGE_PATTERN>
78   - </EXTENSION>
79   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="SCRIPT_ARGS" VALUE="" />
80   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="PORT" VALUE="3000" />
81   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="IP" VALUE="0.0.0.0" />
82   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="DUMMY_APP" VALUE="test/dummy" />
83   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="RAILS_SERVER_TYPE" VALUE="Default" />
84   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="ENVIRONMENT_TYPE" VALUE="production" />
85   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="LAUNCH_JS" VALUE="false" />
86   - <method v="2" />
87   - </configuration>
88   - <configuration default="false" name="Development: kanjai" type="RailsRunConfigurationType" factoryName="Rails">
89   - <predefined_log_file id="RUBY_RAILS_SERVER" enabled="true" />
90   - <module name="kanjai" />
91   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="RUBY_ARGS" VALUE="" />
92   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="WORK DIR" VALUE="$MODULE_DIR$" />
93   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="SHOULD_USE_SDK" VALUE="false" />
94   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="ALTERN_SDK_NAME" VALUE="" />
95   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="myPassParentEnvs" VALUE="true" />
96   - <EXTENSION ID="BundlerRunConfigurationExtension" bundleExecEnabled="false" />
97   - <EXTENSION ID="JRubyRunConfigurationExtension" NailgunExecEnabled="false" />
98   - <EXTENSION ID="RubyCoverageRunConfigurationExtension" track_test_folders="true" runner="rcov">
99   - <COVERAGE_PATTERN ENABLED="true">
100   - <PATTERN REGEXPS="/.rvm/" INCLUDED="false" />
101   - </COVERAGE_PATTERN>
102   - </EXTENSION>
103   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="SCRIPT_ARGS" VALUE="" />
104   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="PORT" VALUE="3000" />
105   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="IP" VALUE="0.0.0.0" />
106   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="DUMMY_APP" VALUE="test/dummy" />
107   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="RAILS_SERVER_TYPE" VALUE="Default" />
108   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="ENVIRONMENT_TYPE" VALUE="development" />
109   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="LAUNCH_JS" VALUE="false" />
110   - <method v="2" />
111   - </configuration>
112   - </shared>
113   - </component>
114   - <component name="NewModuleRootManager">
115   - <content url="file://$MODULE_DIR$">
116   - <sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
117   - </content>
118   - <orderEntry type="jdk" jdkName="rbenv: 2.1.3" jdkType="RUBY_SDK" />
119   - <orderEntry type="sourceFolder" forTests="false" />
120   - <orderEntry type="library" scope="PROVIDED" name="actionmailer (v4.2.6, rbenv: 2.1.3) [gem]" level="application" />
121   - <orderEntry type="library" scope="PROVIDED" name="actionpack (v4.2.6, rbenv: 2.1.3) [gem]" level="application" />
122   - <orderEntry type="library" scope="PROVIDED" name="actionview (v4.2.6, rbenv: 2.1.3) [gem]" level="application" />
123   - <orderEntry type="library" scope="PROVIDED" name="activejob (v4.2.6, rbenv: 2.1.3) [gem]" level="application" />
124   - <orderEntry type="library" scope="PROVIDED" name="activemodel (v4.2.6, rbenv: 2.1.3) [gem]" level="application" />
125   - <orderEntry type="library" scope="PROVIDED" name="activerecord (v4.2.6, rbenv: 2.1.3) [gem]" level="application" />
126   - <orderEntry type="library" scope="PROVIDED" name="activesupport (v4.2.6, rbenv: 2.1.3) [gem]" level="application" />
127   - <orderEntry type="library" scope="PROVIDED" name="acts_as_list (v0.9.5, rbenv: 2.1.3) [gem]" level="application" />
128   - <orderEntry type="library" scope="PROVIDED" name="acts_as_tree (v2.7.0, rbenv: 2.1.3) [gem]" level="application" />
129   - <orderEntry type="library" scope="PROVIDED" name="arel (v6.0.4, rbenv: 2.1.3) [gem]" level="application" />
130   - <orderEntry type="library" scope="PROVIDED" name="aws-sdk (v2.6.32, rbenv: 2.1.3) [gem]" level="application" />
131   - <orderEntry type="library" scope="PROVIDED" name="aws-sdk-core (v2.6.32, rbenv: 2.1.3) [gem]" level="application" />
132   - <orderEntry type="library" scope="PROVIDED" name="aws-sdk-resources (v2.6.32, rbenv: 2.1.3) [gem]" level="application" />
133   - <orderEntry type="library" scope="PROVIDED" name="aws-sigv4 (v1.0.2, rbenv: 2.1.3) [gem]" level="application" />
134   - <orderEntry type="library" scope="PROVIDED" name="backport_new_renderer (v1.0.0, rbenv: 2.1.3) [gem]" level="application" />
135   - <orderEntry type="library" scope="PROVIDED" name="bcrypt (v3.1.11, rbenv: 2.1.3) [gem]" level="application" />
136   - <orderEntry type="library" scope="PROVIDED" name="builder (v3.2.2, rbenv: 2.1.3) [gem]" level="application" />
137   - <orderEntry type="library" scope="PROVIDED" name="bundler (v1.9.0, rbenv: 2.1.3) [gem]" level="application" />
138   - <orderEntry type="library" scope="PROVIDED" name="concurrent-ruby (v1.0.5, rbenv: 2.1.3) [gem]" level="application" />
139   - <orderEntry type="library" scope="PROVIDED" name="daemons (v1.2.6, rbenv: 2.1.3) [gem]" level="application" />
140   - <orderEntry type="library" scope="PROVIDED" name="delayed_job (v4.1.4, rbenv: 2.1.3) [gem]" level="application" />
141   - <orderEntry type="library" scope="PROVIDED" name="delayed_job_active_record (v4.1.2, rbenv: 2.1.3) [gem]" level="application" />
142   - <orderEntry type="library" scope="PROVIDED" name="devise (v4.4.0, rbenv: 2.1.3) [gem]" level="application" />
143   - <orderEntry type="library" scope="PROVIDED" name="diff-lcs (v1.2.5, rbenv: 2.1.3) [gem]" level="application" />
144   - <orderEntry type="library" scope="PROVIDED" name="erubis (v2.7.0, rbenv: 2.1.3) [gem]" level="application" />
145   - <orderEntry type="library" scope="PROVIDED" name="execjs (v2.7.0, rbenv: 2.1.3) [gem]" level="application" />
146   - <orderEntry type="library" scope="PROVIDED" name="factory_girl (v4.7.0, rbenv: 2.1.3) [gem]" level="application" />
147   - <orderEntry type="library" scope="PROVIDED" name="factory_girl_rails (v4.8.0, rbenv: 2.1.3) [gem]" level="application" />
148   - <orderEntry type="library" scope="PROVIDED" name="ffi (v1.9.14, rbenv: 2.1.3) [gem]" level="application" />
149   - <orderEntry type="library" scope="PROVIDED" name="globalid (v0.4.1, rbenv: 2.1.3) [gem]" level="application" />
150   - <orderEntry type="library" scope="PROVIDED" name="i18n (v0.7.0, rbenv: 2.1.3) [gem]" level="application" />
151   - <orderEntry type="library" scope="PROVIDED" name="jbuilder (v2.7.0, rbenv: 2.1.3) [gem]" level="application" />
152   - <orderEntry type="library" scope="PROVIDED" name="jmespath (v1.3.1, rbenv: 2.1.3) [gem]" level="application" />
153   - <orderEntry type="library" scope="PROVIDED" name="jquery-rails (v3.1.2, rbenv: 2.1.3) [gem]" level="application" />
154   - <orderEntry type="library" scope="PROVIDED" name="json (v1.8.3, rbenv: 2.1.3) [gem]" level="application" />
155   - <orderEntry type="library" scope="PROVIDED" name="libv8 (v3.16.14.19, rbenv: 2.1.3) [gem]" level="application" />
156   - <orderEntry type="library" scope="PROVIDED" name="loofah (v2.0.3, rbenv: 2.1.3) [gem]" level="application" />
157   - <orderEntry type="library" scope="PROVIDED" name="mail (v2.7.0, rbenv: 2.1.3) [gem]" level="application" />
158   - <orderEntry type="library" scope="PROVIDED" name="mini_mime (v1.0.0, rbenv: 2.1.3) [gem]" level="application" />
159   - <orderEntry type="library" scope="PROVIDED" name="mini_portile (v0.5.3, rbenv: 2.1.3) [gem]" level="application" />
160   - <orderEntry type="library" scope="PROVIDED" name="minitest (v5.8.4, rbenv: 2.1.3) [gem]" level="application" />
161   - <orderEntry type="library" scope="PROVIDED" name="multi_json (v1.13.1, rbenv: 2.1.3) [gem]" level="application" />
162   - <orderEntry type="library" scope="PROVIDED" name="nokogiri (v1.6.1, rbenv: 2.1.3) [gem]" level="application" />
163   - <orderEntry type="library" scope="PROVIDED" name="orm_adapter (v0.5.0, rbenv: 2.1.3) [gem]" level="application" />
164   - <orderEntry type="library" scope="PROVIDED" name="pg (v0.17.1, rbenv: 2.1.3) [gem]" level="application" />
165   - <orderEntry type="library" scope="PROVIDED" name="rack (v1.6.4, rbenv: 2.1.3) [gem]" level="application" />
166   - <orderEntry type="library" scope="PROVIDED" name="rack-test (v0.6.3, rbenv: 2.1.3) [gem]" level="application" />
167   - <orderEntry type="library" scope="PROVIDED" name="rails (v4.2.7.1, rbenv: 2.1.3) [gem]" level="application" />
168   - <orderEntry type="library" scope="PROVIDED" name="rails-deprecated_sanitizer (v1.0.3, rbenv: 2.1.3) [gem]" level="application" />
169   - <orderEntry type="library" scope="PROVIDED" name="rails-dom-testing (v1.0.7, rbenv: 2.1.3) [gem]" level="application" />
170   - <orderEntry type="library" scope="PROVIDED" name="rails-html-sanitizer (v1.0.3, rbenv: 2.1.3) [gem]" level="application" />
171   - <orderEntry type="library" scope="PROVIDED" name="rails_12factor (v0.0.3, rbenv: 2.1.3) [gem]" level="application" />
172   - <orderEntry type="library" scope="PROVIDED" name="rails_serve_static_assets (v0.0.5, rbenv: 2.1.3) [gem]" level="application" />
173   - <orderEntry type="library" scope="PROVIDED" name="rails_stdout_logging (v0.0.5, rbenv: 2.1.3) [gem]" level="application" />
174   - <orderEntry type="library" scope="PROVIDED" name="railties (v4.2.6, rbenv: 2.1.3) [gem]" level="application" />
175   - <orderEntry type="library" scope="PROVIDED" name="rake (v11.1.2, rbenv: 2.1.3) [gem]" level="application" />
176   - <orderEntry type="library" scope="PROVIDED" name="rb-fsevent (v0.10.2, rbenv: 2.1.3) [gem]" level="application" />
177   - <orderEntry type="library" scope="PROVIDED" name="rb-inotify (v0.9.10, rbenv: 2.1.3) [gem]" level="application" />
178   - <orderEntry type="library" scope="PROVIDED" name="rdoc (v4.3.0, rbenv: 2.1.3) [gem]" level="application" />
179   - <orderEntry type="library" scope="PROVIDED" name="ref (v2.0.0, rbenv: 2.1.3) [gem]" level="application" />
180   - <orderEntry type="library" scope="PROVIDED" name="responders (v2.4.0, rbenv: 2.1.3) [gem]" level="application" />
181   - <orderEntry type="library" scope="PROVIDED" name="rspec-core (v3.4.4, rbenv: 2.1.3) [gem]" level="application" />
182   - <orderEntry type="library" scope="PROVIDED" name="rspec-expectations (v3.4.0, rbenv: 2.1.3) [gem]" level="application" />
183   - <orderEntry type="library" scope="PROVIDED" name="rspec-mocks (v3.4.1, rbenv: 2.1.3) [gem]" level="application" />
184   - <orderEntry type="library" scope="PROVIDED" name="rspec-rails (v3.4.2, rbenv: 2.1.3) [gem]" level="application" />
185   - <orderEntry type="library" scope="PROVIDED" name="rspec-support (v3.4.1, rbenv: 2.1.3) [gem]" level="application" />
186   - <orderEntry type="library" scope="PROVIDED" name="sass (v3.5.5, rbenv: 2.1.3) [gem]" level="application" />
187   - <orderEntry type="library" scope="PROVIDED" name="sass-listen (v4.0.0, rbenv: 2.1.3) [gem]" level="application" />
188   - <orderEntry type="library" scope="PROVIDED" name="sass-rails (v5.0.7, rbenv: 2.1.3) [gem]" level="application" />
189   - <orderEntry type="library" scope="PROVIDED" name="sdoc (v0.4.2, rbenv: 2.1.3) [gem]" level="application" />
190   - <orderEntry type="library" scope="PROVIDED" name="sprockets (v3.7.1, rbenv: 2.1.3) [gem]" level="application" />
191   - <orderEntry type="library" scope="PROVIDED" name="sprockets-rails (v3.2.1, rbenv: 2.1.3) [gem]" level="application" />
192   - <orderEntry type="library" scope="PROVIDED" name="therubyracer (v0.12.2, rbenv: 2.1.3) [gem]" level="application" />
193   - <orderEntry type="library" scope="PROVIDED" name="thor (v0.19.1, rbenv: 2.1.3) [gem]" level="application" />
194   - <orderEntry type="library" scope="PROVIDED" name="thread_safe (v0.3.5, rbenv: 2.1.3) [gem]" level="application" />
195   - <orderEntry type="library" scope="PROVIDED" name="tilt (v2.0.8, rbenv: 2.1.3) [gem]" level="application" />
196   - <orderEntry type="library" scope="PROVIDED" name="tzinfo (v1.2.2, rbenv: 2.1.3) [gem]" level="application" />
197   - <orderEntry type="library" scope="PROVIDED" name="uglifier (v4.1.3, rbenv: 2.1.3) [gem]" level="application" />
198   - <orderEntry type="library" scope="PROVIDED" name="warden (v1.2.7, rbenv: 2.1.3) [gem]" level="application" />
199   - </component>
200   - <component name="RModuleSettingsStorage">
201   - <LOAD_PATH number="0" />
202   - <I18N_FOLDERS number="1" string0="$MODULE_DIR$/config/locales" />
203   - </component>
204   -</module>
\ No newline at end of file
1   -<?xml version="1.0" encoding="UTF-8"?>
2   -<project version="4">
3   - <component name="ProjectRootManager" version="2" project-jdk-name="rbenv: 1.8.7-p375" project-jdk-type="RUBY_SDK" />
4   -</project>
\ No newline at end of file
1   -<?xml version="1.0" encoding="UTF-8"?>
2   -<project version="4">
3   - <component name="ProjectModuleManager">
4   - <modules>
5   - <module fileurl="file://$PROJECT_DIR$/.idea/kanjai.iml" filepath="$PROJECT_DIR$/.idea/kanjai.iml" />
6   - </modules>
7   - </component>
8   -</project>
\ No newline at end of file
1   -<component name="ProjectRunConfigurationManager">
2   - <configuration default="false" name="Development: kanjai" type="RailsRunConfigurationType" factoryName="Rails">
3   - <predefined_log_file id="RUBY_RAILS_SERVER" enabled="true" />
4   - <module name="kanjai" />
5   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="RUBY_ARGS" VALUE="-e $stdout.sync=true;$stderr.sync=true;load($0=ARGV.shift)" />
6   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="WORK DIR" VALUE="$MODULE_DIR$" />
7   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="SHOULD_USE_SDK" VALUE="false" />
8   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="ALTERN_SDK_NAME" VALUE="" />
9   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="myPassParentEnvs" VALUE="true" />
10   - <envs />
11   - <EXTENSION ID="BundlerRunConfigurationExtension" bundleExecEnabled="false" />
12   - <EXTENSION ID="JRubyRunConfigurationExtension" NailgunExecEnabled="false" />
13   - <EXTENSION ID="RubyCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" track_test_folders="true" runner="rcov">
14   - <COVERAGE_PATTERN ENABLED="true">
15   - <PATTERN REGEXPS="/.rvm/" INCLUDED="false" />
16   - </COVERAGE_PATTERN>
17   - </EXTENSION>
18   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="SCRIPT_ARGS" VALUE="" />
19   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="PORT" VALUE="3000" />
20   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="IP" VALUE="0.0.0.0" />
21   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="DUMMY_APP" VALUE="test/dummy" />
22   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="RAILS_SERVER_TYPE" VALUE="Default" />
23   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="ENVIRONMENT_TYPE" VALUE="development" />
24   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="LAUNCH_JS" VALUE="false" />
25   - <method />
26   - </configuration>
27   -</component>
\ No newline at end of file
1   -<component name="ProjectRunConfigurationManager">
2   - <configuration default="false" name="Production: kanjai" type="RailsRunConfigurationType" factoryName="Rails">
3   - <predefined_log_file id="RUBY_RAILS_SERVER" enabled="true" />
4   - <module name="kanjai" />
5   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="RUBY_ARGS" VALUE="-e $stdout.sync=true;$stderr.sync=true;load($0=ARGV.shift)" />
6   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="WORK DIR" VALUE="$MODULE_DIR$" />
7   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="SHOULD_USE_SDK" VALUE="false" />
8   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="ALTERN_SDK_NAME" VALUE="" />
9   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="myPassParentEnvs" VALUE="true" />
10   - <envs />
11   - <EXTENSION ID="BundlerRunConfigurationExtension" bundleExecEnabled="false" />
12   - <EXTENSION ID="JRubyRunConfigurationExtension" NailgunExecEnabled="false" />
13   - <EXTENSION ID="RubyCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" track_test_folders="true" runner="rcov">
14   - <COVERAGE_PATTERN ENABLED="true">
15   - <PATTERN REGEXPS="/.rvm/" INCLUDED="false" />
16   - </COVERAGE_PATTERN>
17   - </EXTENSION>
18   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="SCRIPT_ARGS" VALUE="" />
19   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="PORT" VALUE="3000" />
20   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="IP" VALUE="0.0.0.0" />
21   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="DUMMY_APP" VALUE="test/dummy" />
22   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="RAILS_SERVER_TYPE" VALUE="Default" />
23   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="ENVIRONMENT_TYPE" VALUE="production" />
24   - <RAILS_SERVER_CONFIG_SETTINGS_ID NAME="LAUNCH_JS" VALUE="false" />
25   - <method />
26   - </configuration>
27   -</component>
\ No newline at end of file
1   -<component name="ProjectRunConfigurationManager">
2   - <configuration default="false" name="spec: kanjai" type="RakeRunConfigurationType" factoryName="Rake">
3   - <module name="kanjai" />
4   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="RUBY_ARGS" VALUE="-e $stdout.sync=true;$stderr.sync=true;load($0=ARGV.shift)" />
5   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="WORK DIR" VALUE="$MODULE_DIR$" />
6   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="SHOULD_USE_SDK" VALUE="false" />
7   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="ALTERN_SDK_NAME" VALUE="" />
8   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="myPassParentEnvs" VALUE="true" />
9   - <envs />
10   - <EXTENSION ID="BundlerRunConfigurationExtension" bundleExecEnabled="false" />
11   - <EXTENSION ID="JRubyRunConfigurationExtension" NailgunExecEnabled="false" />
12   - <EXTENSION ID="RubyCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" track_test_folders="true" runner="rcov">
13   - <COVERAGE_PATTERN ENABLED="true">
14   - <PATTERN REGEXPS="/.rvm/" INCLUDED="false" />
15   - </COVERAGE_PATTERN>
16   - </EXTENSION>
17   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="RAKE_TASK_NAME" VALUE="spec" />
18   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="RAKE_TASK_ARGS" VALUE="" />
19   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="RAKE_TASK_ATTACHED_TEST_FRAMEWORKS" VALUE=":rspec " />
20   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="RAKE_TASK_OPTION_TRACE" VALUE="false" />
21   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="RAKE_TASK_OPTION_DRYRUN" VALUE="false" />
22   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="RAKE_TASK_OPTION_PREREQS" VALUE="false" />
23   - <method />
24   - </configuration>
25   -</component>
\ No newline at end of file
1   -<component name="ProjectRunConfigurationManager">
2   - <configuration default="false" name="test: kanjai" type="RakeRunConfigurationType" factoryName="Rake">
3   - <module name="kanjai" />
4   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="RUBY_ARGS" VALUE="-e $stdout.sync=true;$stderr.sync=true;load($0=ARGV.shift)" />
5   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="WORK DIR" VALUE="$MODULE_DIR$" />
6   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="SHOULD_USE_SDK" VALUE="false" />
7   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="ALTERN_SDK_NAME" VALUE="" />
8   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="myPassParentEnvs" VALUE="true" />
9   - <envs>
10   - <env name="RAILS_ENV" value="test" />
11   - </envs>
12   - <EXTENSION ID="BundlerRunConfigurationExtension" bundleExecEnabled="false" />
13   - <EXTENSION ID="JRubyRunConfigurationExtension" NailgunExecEnabled="false" />
14   - <EXTENSION ID="RubyCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" track_test_folders="true" runner="rcov">
15   - <COVERAGE_PATTERN ENABLED="true">
16   - <PATTERN REGEXPS="/.rvm/" INCLUDED="false" />
17   - </COVERAGE_PATTERN>
18   - </EXTENSION>
19   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="RAKE_TASK_NAME" VALUE="test" />
20   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="RAKE_TASK_ARGS" VALUE="" />
21   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="RAKE_TASK_ATTACHED_TEST_FRAMEWORKS" VALUE=":test_unit " />
22   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="RAKE_TASK_OPTION_TRACE" VALUE="false" />
23   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="RAKE_TASK_OPTION_DRYRUN" VALUE="false" />
24   - <RAKE_RUN_CONFIG_SETTINGS_ID NAME="RAKE_TASK_OPTION_PREREQS" VALUE="false" />
25   - <method />
26   - </configuration>
27   -</component>
\ No newline at end of file
1   -<component name="DependencyValidationManager">
2   - <state>
3   - <option name="SKIP_IMPORT_STATEMENTS" value="false" />
4   - </state>
5   -</component>
\ No newline at end of file
1   -<?xml version="1.0" encoding="UTF-8"?>
2   -<project version="4">
3   - <component name="VcsDirectoryMappings">
4   - <mapping directory="$PROJECT_DIR$" vcs="Git" />
5   - </component>
6   -</project>
\ No newline at end of file
1   -<?xml version="1.0" encoding="UTF-8"?>
2   -<project version="4">
3   - <component name="ChangeListManager">
4   - <list default="true" id="cbbcb0f9-d203-4967-aa4d-c08a939c7df0" name="Default" comment="">
5   - <change beforePath="$PROJECT_DIR$/.idea/kanjai.iml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/kanjai.iml" afterDir="false" />
6   - <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
7   - <change beforePath="$PROJECT_DIR$/Gemfile.lock" beforeDir="false" afterPath="$PROJECT_DIR$/Gemfile.lock" afterDir="false" />
8   - </list>
9   - <ignored path="kanjai.iws" />
10   - <ignored path=".idea/workspace.xml" />
11   - <ignored path=".idea/dataSources.local.xml" />
12   - <option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
13   - <option name="SHOW_DIALOG" value="false" />
14   - <option name="HIGHLIGHT_CONFLICTS" value="true" />
15   - <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
16   - <option name="LAST_RESOLUTION" value="IGNORE" />
17   - </component>
18   - <component name="CreatePatchCommitExecutor">
19   - <option name="PATCH_PATH" value="" />
20   - </component>
21   - <component name="FUSProjectUsageTrigger">
22   - <session id="1963050572">
23   - <usages-collector id="statistics.lifecycle.project">
24   - <counts>
25   - <entry key="project.closed" value="1" />
26   - <entry key="project.open.time.8" value="1" />
27   - <entry key="project.open.time.9" value="1" />
28   - <entry key="project.opened" value="2" />
29   - </counts>
30   - </usages-collector>
31   - </session>
32   - </component>
33   - <component name="FavoritesManager">
34   - <favorites_list name="kanjai" />
35   - </component>
36   - <component name="FileEditorManager">
37   - <leaf SIDE_TABS_SIZE_LIMIT_KEY="300">
38   - <file pinned="false" current-in-tab="false">
39   - <entry file="file://$PROJECT_DIR$/config/initializers/aws.rb">
40   - <provider selected="true" editor-type-id="text-editor">
41   - <state relative-caret-position="75">
42   - <caret line="5" column="57" selection-start-line="5" selection-start-column="41" selection-end-line="5" selection-end-column="57" />
43   - </state>
44   - </provider>
45   - </entry>
46   - </file>
47   - <file pinned="false" current-in-tab="false">
48   - <entry file="file://$PROJECT_DIR$/lib/kanjai/template_generator.rb">
49   - <provider selected="true" editor-type-id="text-editor">
50   - <state relative-caret-position="3390">
51   - <caret line="226" column="42" selection-start-line="226" selection-start-column="23" selection-end-line="226" selection-end-column="42" />
52   - </state>
53   - </provider>
54   - </entry>
55   - </file>
56   - <file pinned="false" current-in-tab="false">
57   - <entry file="file://$PROJECT_DIR$/app/controllers/kanjai/pages_controller.rb">
58   - <provider selected="true" editor-type-id="text-editor">
59   - <state relative-caret-position="465">
60   - <caret line="31" selection-start-line="31" selection-end-line="31" />
61   - </state>
62   - </provider>
63   - </entry>
64   - </file>
65   - <file pinned="false" current-in-tab="true">
66   - <entry file="file://$PROJECT_DIR$/lib/kanjai/version.rb">
67   - <provider selected="true" editor-type-id="text-editor">
68   - <state relative-caret-position="45">
69   - <caret line="3" selection-start-line="3" selection-end-line="3" />
70   - </state>
71   - </provider>
72   - </entry>
73   - </file>
74   - <file pinned="false" current-in-tab="false">
75   - <entry file="file://$PROJECT_DIR$/Gemfile.lock">
76   - <provider selected="true" editor-type-id="text-editor">
77   - <state relative-caret-position="795">
78   - <caret line="53" column="13" selection-start-line="53" selection-start-column="13" selection-end-line="53" selection-end-column="13" />
79   - </state>
80   - </provider>
81   - </entry>
82   - </file>
83   - <file pinned="false" current-in-tab="false">
84   - <entry file="file://$PROJECT_DIR$/config/initializers/devise.rb">
85   - <provider selected="true" editor-type-id="text-editor">
86   - <state relative-caret-position="90">
87   - <caret line="6" column="46" selection-start-line="6" selection-start-column="22" selection-end-line="6" selection-end-column="46" />
88   - </state>
89   - </provider>
90   - </entry>
91   - </file>
92   - <file pinned="false" current-in-tab="false">
93   - <entry file="file://$PROJECT_DIR$/config/initializers/admin.rb">
94   - <provider selected="true" editor-type-id="text-editor">
95   - <state relative-caret-position="45">
96   - <caret line="3" column="46" selection-start-line="3" selection-start-column="46" selection-end-line="3" selection-end-column="46" />
97   - </state>
98   - </provider>
99   - </entry>
100   - </file>
101   - <file pinned="false" current-in-tab="false">
102   - <entry file="file://$PROJECT_DIR$/lib/kanjai.rb">
103   - <provider selected="true" editor-type-id="text-editor" />
104   - </entry>
105   - </file>
106   - <file pinned="false" current-in-tab="false">
107   - <entry file="file://$PROJECT_DIR$/lib/kanjai/engine.rb">
108   - <provider selected="true" editor-type-id="text-editor" />
109   - </entry>
110   - </file>
111   - <file pinned="false" current-in-tab="false">
112   - <entry file="file://$PROJECT_DIR$/db/migrate/20160707115443_add_show_public_only_to_kanjai_pages.rb">
113   - <provider selected="true" editor-type-id="text-editor">
114   - <state relative-caret-position="30">
115   - <caret line="2" column="73" selection-start-line="2" selection-start-column="4" selection-end-line="2" selection-end-column="73" />
116   - </state>
117   - </provider>
118   - </entry>
119   - </file>
120   - </leaf>
121   - </component>
122   - <component name="FindInProjectRecents">
123   - <findStrings>
124   - <find>check_p</find>
125   - <find>check_permission</find>
126   - <find>admin_email</find>
127   - <find>INCLUDE_JS_FILE</find>
128   - <find>files = $.makeArray(fileInput.prop('files'));</find>
129   - <find>If the files property is not available, the browser does</find>
130   - <find>If the files property is not available, the browser does not</find>
131   - <find>if (cookieValue.length &gt; 0) break</find>
132   - <find>Extracts flash array stored in cookie and clears</find>
133   - <find>UnobtrusiveFlash</find>
134   - <find>pa</find>
135   - <find>paper</find>
136   - <find>S3_BUCKET</find>
137   - <find>fil</find>
138   - <find>fileuploa</find>
139   - <find>fileupload</find>
140   - <find>help-block</find>
141   - <find>unzip_c</find>
142   - <find>page_template</find>
143   - <find>setTemplateContent</find>
144   - <find>form</find>
145   - <find>###FORM_ACTION###</find>
146   - <find>form_subject</find>
147   - <find>def get_marker_type</find>
148   - <find>sqlite3</find>
149   - <find>sqli</find>
150   - <find>show_public_only</find>
151   - <find>UserSession</find>
152   - <find>User</find>
153   - <find>KANJAI_DOMAIN</find>
154   - </findStrings>
155   - <dirStrings>
156   - <dir>$PROJECT_DIR$/app/controllers</dir>
157   - <dir>$PROJECT_DIR$/app/assets/javascripts</dir>
158   - <dir>$PROJECT_DIR$</dir>
159   - <dir>$PROJECT_DIR$/app</dir>
160   - </dirStrings>
161   - </component>
162   - <component name="Git.Settings">
163   - <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
164   - </component>
165   - <component name="IdeDocumentHistory">
166   - <option name="CHANGED_PATHS">
167   - <list>
168   - <option value="$PROJECT_DIR$/app/assets/stylesheets/kanjai/fileinput.css" />
169   - <option value="$PROJECT_DIR$/app/assets/stylesheets/kanjai/frontend.css.scss" />
170   - <option value="$PROJECT_DIR$/app/assets/javascripts/kanjai/frontend.js" />
171   - <option value="$PROJECT_DIR$/app/assets/javascripts/kanjai/admin/html_generator.js" />
172   - <option value="$PROJECT_DIR$/app/assets/javascripts/kanjai/frontend/html_editor.js" />
173   - <option value="$PROJECT_DIR$/db/migrate/20160804133136_add_image_link_to_kanjai_images.rb" />
174   - <option value="$PROJECT_DIR$/app/views/kanjai/admin/pages/get_gallery.html.erb" />
175   - <option value="$PROJECT_DIR$/app/assets/stylesheets/kanjai/admin/admin.css.scss" />
176   - <option value="$PROJECT_DIR$/app/models/kanjai/image.rb" />
177   - <option value="$PROJECT_DIR$/app/models/kanjai/page.rb" />
178   - <option value="$PROJECT_DIR$/app/views/kanjai/admin/pages/_gallery_exist_images.html.erb" />
179   - <option value="$PROJECT_DIR$/app/views/kanjai/admin/pages/gallery.html.erb" />
180   - <option value="$PROJECT_DIR$/app/views/kanjai/admin/pages/update_gallery.js.erb" />
181   - <option value="$PROJECT_DIR$/app/views/kanjai/admin/pages/_preview.html.erb" />
182   - <option value="$PROJECT_DIR$/app/views/kanjai/admin/pages/delete_gallery_image.js.erb" />
183   - <option value="$PROJECT_DIR$/app/assets/stylesheets/kanjai/general_admin.css.scss" />
184   - <option value="$PROJECT_DIR$/app/helpers/kanjai/admin/pages_helper.rb" />
185   - <option value="$PROJECT_DIR$/lib/kanjai/content_function.rb" />
186   - <option value="$PROJECT_DIR$/app/views/kanjai/pages/show.pdf.erb" />
187   - <option value="$PROJECT_DIR$/app/assets/javascripts/kanjai/admin/admin.js" />
188   - <option value="$PROJECT_DIR$/lib/zip.rb" />
189   - <option value="$PROJECT_DIR$/app/views/layouts/kanjai/admin.html.erb" />
190   - <option value="$PROJECT_DIR$/app/views/kanjai/admin/admin_users/index.html.erb" />
191   - <option value="$PROJECT_DIR$/app/views/kanjai/admin/admin_users/new.html.erb" />
192   - <option value="$PROJECT_DIR$/app/views/kanjai/admin/admin_users/_form.html.erb" />
193   - <option value="$PROJECT_DIR$/app/controllers/kanjai/admin/admin_users_controller.rb" />
194   - <option value="$PROJECT_DIR$/config/locales/en.yml" />
195   - <option value="$PROJECT_DIR$/app/views/kanjai/admin/admin_users/edit.html.erb" />
196   - <option value="$PROJECT_DIR$/app/controllers/kanjai/admin_controller.rb" />
197   - <option value="$PROJECT_DIR$/app/views/kanjai/admin/pages/show_editor.html.erb" />
198   - <option value="$PROJECT_DIR$/db/migrate/20171214071607_add_form_data_to_page_content_marker.rb" />
199   - <option value="$PROJECT_DIR$/app/models/kanjai/page_content.rb" />
200   - <option value="$PROJECT_DIR$/config/routes.rb" />
201   - <option value="$PROJECT_DIR$/app/mailers/application_mailer.rb" />
202   - <option value="$PROJECT_DIR$/db/migrate/20171214092747_add_from_to_mai_to_page_content_marker.rb" />
203   - <option value="$PROJECT_DIR$/app/mailers/kanjai_mailer.rb" />
204   - <option value="$PROJECT_DIR$/app/views/kanjai_mailer/send_mail.html.erb" />
205   - <option value="$PROJECT_DIR$/db/migrate/20171214094525_add_answer_text_to_page_content_marker.rb" />
206   - <option value="$PROJECT_DIR$/app/controllers/kanjai/admin/pages_controller.rb" />
207   - <option value="$PROJECT_DIR$/app/controllers/kanjai/form_controller.rb" />
208   - <option value="$PROJECT_DIR$/kanjai.gemspec" />
209   - <option value="$PROJECT_DIR$/app/controllers/kanjai/site_controller.rb" />
210   - <option value="$PROJECT_DIR$/app/assets/javascripts/kanjai/admin/jquery.fileupload.js" />
211   - <option value="$PROJECT_DIR$/app/models/kanjai/page_template.rb" />
212   - <option value="$PROJECT_DIR$/app/views/kanjai/pages/show.html.erb" />
213   - <option value="$PROJECT_DIR$/lib/kanjai/template_generator.rb" />
214   - <option value="$PROJECT_DIR$/app/views/kanjai/admin/pages/content_types/_content.html.erb" />
215   - <option value="$PROJECT_DIR$/config/initializers/devise.rb" />
216   - <option value="$PROJECT_DIR$/app/controllers/kanjai/pages_controller.rb" />
217   - <option value="$PROJECT_DIR$/config/initializers/admin.rb" />
218   - <option value="$PROJECT_DIR$/lib/kanjai/version.rb" />
219   - </list>
220   - </option>
221   - </component>
222   - <component name="JsBuildToolGruntFileManager" detection-done="true" sorting="DEFINITION_ORDER" />
223   - <component name="JsBuildToolPackageJson" detection-done="true" sorting="DEFINITION_ORDER" />
224   - <component name="JsGulpfileManager">
225   - <detection-done>true</detection-done>
226   - <sorting>DEFINITION_ORDER</sorting>
227   - </component>
228   - <component name="ProjectFrameBounds" extendedState="6">
229   - <option name="y" value="23" />
230   - <option name="width" value="1280" />
231   - <option name="height" value="728" />
232   - </component>
233   - <component name="ProjectLevelVcsManager" settingsEditedManually="true" />
234   - <component name="ProjectView">
235   - <navigator proportions="" version="1">
236   - <foldersAlwaysOnTop value="true" />
237   - </navigator>
238   - <panes>
239   - <pane id="ProjectPane">
240   - <subPane>
241   - <expand>
242   - <path>
243   - <item name="kanjai" type="b2602c69:ProjectViewProjectNode" />
244   - <item name="kanjai" type="462c0819:PsiDirectoryNode" />
245   - </path>
246   - <path>
247   - <item name="kanjai" type="b2602c69:ProjectViewProjectNode" />
248   - <item name="kanjai" type="462c0819:PsiDirectoryNode" />
249   - <item name="config" type="462c0819:PsiDirectoryNode" />
250   - </path>
251   - <path>
252   - <item name="kanjai" type="b2602c69:ProjectViewProjectNode" />
253   - <item name="kanjai" type="462c0819:PsiDirectoryNode" />
254   - <item name="config" type="462c0819:PsiDirectoryNode" />
255   - <item name="initializers" type="462c0819:PsiDirectoryNode" />
256   - </path>
257   - <path>
258   - <item name="kanjai" type="b2602c69:ProjectViewProjectNode" />
259   - <item name="kanjai" type="462c0819:PsiDirectoryNode" />
260   - <item name="lib" type="462c0819:PsiDirectoryNode" />
261   - </path>
262   - <path>
263   - <item name="kanjai" type="b2602c69:ProjectViewProjectNode" />
264   - <item name="kanjai" type="462c0819:PsiDirectoryNode" />
265   - <item name="lib" type="462c0819:PsiDirectoryNode" />
266   - <item name="kanjai" type="462c0819:PsiDirectoryNode" />
267   - </path>
268   - <path>
269   - <item name="kanjai" type="b2602c69:ProjectViewProjectNode" />
270   - <item name="kanjai" type="462c0819:PsiDirectoryNode" />
271   - <item name="lib" type="462c0819:PsiDirectoryNode" />
272   - <item name="tasks" type="462c0819:PsiDirectoryNode" />
273   - </path>
274   - </expand>
275   - <select />
276   - </subPane>
277   - </pane>
278   - <pane id="Scope" />
279   - <pane id="RailsProjectView" />
280   - </panes>
281   - </component>
282   - <component name="PropertiesComponent">
283   - <property name="HbShouldOpenHtmlAsHb" value="" />
284   - <property name="WebServerToolWindowFactoryState" value="false" />
285   - <property name="last_opened_file_path" value="$PROJECT_DIR$" />
286   - <property name="recentsLimit" value="5" />
287   - </component>
288   - <component name="RecentsManager">
289   - <key name="MoveFile.RECENT_KEYS">
290   - <recent name="$PROJECT_DIR$/app/assets/images/kanjai/fileinput" />
291   - <recent name="$PROJECT_DIR$/app/assets/stylesheets/kanjai" />
292   - <recent name="$PROJECT_DIR$/app/assets/javascripts/kanjai/lib" />
293   - </key>
294   - <key name="CopyFile.RECENT_KEYS">
295   - <recent name="$PROJECT_DIR$/app/mailers" />
296   - <recent name="$PROJECT_DIR$/app/views/kanjai/admin/admin_users" />
297   - <recent name="$PROJECT_DIR$/config/initializers" />
298   - <recent name="$PROJECT_DIR$/bin" />
299   - <recent name="$PROJECT_DIR$/app/assets/stylesheets/kanjai/general" />
300   - </key>
301   - </component>
302   - <component name="RunDashboard">
303   - <option name="ruleStates">
304   - <list>
305   - <RuleState>
306   - <option name="name" value="ConfigurationTypeDashboardGroupingRule" />
307   - </RuleState>
308   - <RuleState>
309   - <option name="name" value="StatusDashboardGroupingRule" />
310   - </RuleState>
311   - </list>
312   - </option>
313   - </component>
314   - <component name="RunManager" selected="Rails.Development: kanjai">
315   - <configuration default="true" type="js.build_tools.gulp" factoryName="Gulp.js">
316   - <node-interpreter>project</node-interpreter>
317   - <node-options />
318   - <gulpfile />
319   - <tasks />
320   - <arguments />
321   - <pass-parent-envs>true</pass-parent-envs>
322   - <method v="2" />
323   - </configuration>
324   - <list>
325   - <item itemvalue="Rake.test: kanjai" />
326   - <item itemvalue="Rake.spec: kanjai" />
327   - <item itemvalue="Rails.Production: kanjai" />
328   - <item itemvalue="Rails.Development: kanjai" />
329   - </list>
330   - </component>
331   - <component name="SpringUtil" SPRING_PRE_LOADER_OPTION="true" />
332   - <component name="SvnConfiguration">
333   - <configuration />
334   - </component>
335   - <component name="TaskManager">
336   - <task active="true" id="Default" summary="Default task">
337   - <changelist id="cbbcb0f9-d203-4967-aa4d-c08a939c7df0" name="Default" comment="" />
338   - <created>1461667396774</created>
339   - <option name="number" value="Default" />
340   - <option name="presentableId" value="Default" />
341   - <updated>1461667396774</updated>
342   - <workItem from="1494966983627" duration="731000" />
343   - <workItem from="1495090952619" duration="1573000" />
344   - <workItem from="1495108372095" duration="2000" />
345   - <workItem from="1498808617180" duration="1037000" />
346   - <workItem from="1498836423959" duration="4000" />
347   - <workItem from="1500931211896" duration="152000" />
348   - <workItem from="1500931637579" duration="304000" />
349   - <workItem from="1501482504677" duration="10000" />
350   - <workItem from="1513232887722" duration="10776000" />
351   - <workItem from="1513283335284" duration="121000" />
352   - <workItem from="1513543303254" duration="7193000" />
353   - <workItem from="1516654861781" duration="654000" />
354   - <workItem from="1519076359527" duration="5272000" />
355   - <workItem from="1519386347440" duration="1120000" />
356   - <workItem from="1519477125017" duration="2000" />
357   - <workItem from="1521110918867" duration="606000" />
358   - <workItem from="1521116413044" duration="527000" />
359   - <workItem from="1521124710073" duration="38000" />
360   - <workItem from="1522062575414" duration="786000" />
361   - <workItem from="1524563703669" duration="29000" />
362   - <workItem from="1524565240546" duration="602000" />
363   - <workItem from="1526849333726" duration="2848000" />
364   - <workItem from="1526898064400" duration="244000" />
365   - <workItem from="1526992788869" duration="3744000" />
366   - <workItem from="1527228957742" duration="663000" />
367   - <workItem from="1527239274712" duration="965000" />
368   - <workItem from="1527250151106" duration="1359000" />
369   - <workItem from="1528795289630" duration="58000" />
370   - <workItem from="1528797772730" duration="2306000" />
371   - <workItem from="1528983596909" duration="231000" />
372   - <workItem from="1528984727408" duration="942000" />
373   - <workItem from="1529067232509" duration="427000" />
374   - <workItem from="1529134009751" duration="477000" />
375   - <workItem from="1530563947793" duration="325000" />
376   - <workItem from="1532497382207" duration="775000" />
377   - <workItem from="1532528310773" duration="526000" />
378   - <workItem from="1532617523201" duration="881000" />
379   - <workItem from="1533023763618" duration="569000" />
380   - <workItem from="1533043884272" duration="812000" />
381   - <workItem from="1536316862776" duration="652000" />
382   - <workItem from="1536432181981" duration="68000" />
383   - </task>
384   - <servers />
385   - </component>
386   - <component name="TimeTrackingManager">
387   - <option name="totallyTimeSpent" value="50411000" />
388   - </component>
389   - <component name="ToolWindowManager">
390   - <frame x="0" y="23" width="1280" height="728" extended-state="6" />
391   - <layout>
392   - <window_info active="true" content_ui="combo" id="Project" order="0" visible="true" weight="0.3861066" />
393   - <window_info id="Structure" order="1" side_tool="true" weight="0.25" />
394   - <window_info id="Favorites" order="2" side_tool="true" />
395   - <window_info anchor="bottom" id="Message" order="0" />
396   - <window_info anchor="bottom" id="Find" order="1" weight="0.32930514" />
397   - <window_info anchor="bottom" id="Run" order="2" />
398   - <window_info anchor="bottom" id="Debug" order="3" weight="0.4" />
399   - <window_info anchor="bottom" id="Cvs" order="4" weight="0.25" />
400   - <window_info anchor="bottom" id="Inspection" order="5" weight="0.4" />
401   - <window_info anchor="bottom" id="TODO" order="6" />
402   - <window_info anchor="bottom" id="Changes" order="7" />
403   - <window_info anchor="bottom" id="Terminal" order="8" />
404   - <window_info anchor="bottom" id="Version Control" order="9" />
405   - <window_info anchor="bottom" id="Event Log" order="10" side_tool="true" weight="0.32930514" />
406   - <window_info anchor="bottom" id="Application Servers" order="11" />
407   - <window_info anchor="bottom" id="Messages" order="12" weight="0.32930514" />
408   - <window_info anchor="bottom" id="Docker" order="13" show_stripe_button="false" />
409   - <window_info anchor="bottom" id="Database Changes" order="14" show_stripe_button="false" />
410   - <window_info anchor="right" id="Commander" internal_type="SLIDING" order="0" type="SLIDING" weight="0.4" />
411   - <window_info anchor="right" id="Ant Build" order="1" weight="0.25" />
412   - <window_info anchor="right" content_ui="combo" id="Hierarchy" order="2" weight="0.25" />
413   - <window_info anchor="right" id="Database" order="3" />
414   - </layout>
415   - </component>
416   - <component name="TypeScriptGeneratedFilesManager">
417   - <option name="version" value="1" />
418   - </component>
419   - <component name="Vcs.Log.UiProperties">
420   - <option name="RECENTLY_FILTERED_USER_GROUPS">
421   - <collection />
422   - </option>
423   - <option name="RECENTLY_FILTERED_BRANCH_GROUPS">
424   - <collection />
425   - </option>
426   - </component>
427   - <component name="VcsContentAnnotationSettings">
428   - <option name="myLimit" value="2678400000" />
429   - </component>
430   - <component name="editorHistoryManager">
431   - <entry file="file://$PROJECT_DIR$/kanjai.gemspec">
432   - <provider selected="true" editor-type-id="text-editor">
433   - <state relative-caret-position="300">
434   - <caret line="20" column="41" selection-start-line="20" selection-start-column="41" selection-end-line="20" selection-end-column="41" />
435   - </state>
436   - </provider>
437   - </entry>
438   - <entry file="file://$PROJECT_DIR$/app/models/kanjai/page_content.rb">
439   - <provider selected="true" editor-type-id="text-editor">
440   - <state relative-caret-position="2115">
441   - <caret line="141" column="119" selection-start-line="141" selection-start-column="119" selection-end-line="141" selection-end-column="119" />
442   - </state>
443   - </provider>
444   - </entry>
445   - <entry file="file://$PROJECT_DIR$/app/views/kanjai/pages/show.html.erb">
446   - <provider selected="true" editor-type-id="text-editor">
447   - <state relative-caret-position="15">
448   - <caret line="1" column="27" selection-start-line="1" selection-start-column="27" selection-end-line="1" selection-end-column="27" />
449   - </state>
450   - </provider>
451   - </entry>
452   - <entry file="file://$PROJECT_DIR$/config/routes.rb">
453   - <provider selected="true" editor-type-id="text-editor">
454   - <state relative-caret-position="855">
455   - <caret line="57" column="32" selection-start-line="57" selection-start-column="17" selection-end-line="57" selection-end-column="32" />
456   - </state>
457   - </provider>
458   - </entry>
459   - <entry file="file://$PROJECT_DIR$/app/views/kanjai_mailer/send_mail.html.erb">
460   - <provider selected="true" editor-type-id="text-editor">
461   - <state relative-caret-position="45">
462   - <caret line="3" column="11" selection-start-line="3" selection-start-column="3" selection-end-line="3" selection-end-column="11" />
463   - </state>
464   - </provider>
465   - </entry>
466   - <entry file="file://$PROJECT_DIR$/app/mailers/kanjai_mailer.rb">
467   - <provider selected="true" editor-type-id="text-editor">
468   - <state relative-caret-position="60">
469   - <caret line="4" column="5" selection-start-line="4" selection-start-column="5" selection-end-line="4" selection-end-column="5" />
470   - </state>
471   - </provider>
472   - </entry>
473   - <entry file="file://$PROJECT_DIR$/app/controllers/kanjai/form_controller.rb">
474   - <provider selected="true" editor-type-id="text-editor">
475   - <state relative-caret-position="75">
476   - <caret line="5" column="44" selection-start-line="5" selection-start-column="32" selection-end-line="5" selection-end-column="44" />
477   - </state>
478   - </provider>
479   - </entry>
480   - <entry file="file://$PROJECT_DIR$/app/models/kanjai/page_content_marker.rb">
481   - <provider selected="true" editor-type-id="text-editor">
482   - <state relative-caret-position="255">
483   - <caret line="17" column="65" selection-start-line="17" selection-start-column="53" selection-end-line="17" selection-end-column="65" />
484   - </state>
485   - </provider>
486   - </entry>
487   - <entry file="file://$PROJECT_DIR$/app/views/kanjai/admin/pages/content_types/_content.html.erb">
488   - <provider selected="true" editor-type-id="text-editor">
489   - <state relative-caret-position="15">
490   - <caret line="1" column="121" selection-start-line="1" selection-start-column="121" selection-end-line="1" selection-end-column="121" />
491   - </state>
492   - </provider>
493   - </entry>
494   - <entry file="file://$PROJECT_DIR$/app/controllers/kanjai/admin/page_templates_controller.rb">
495   - <provider selected="true" editor-type-id="text-editor">
496   - <state relative-caret-position="1500">
497   - <caret line="100" column="21" selection-start-line="100" selection-start-column="6" selection-end-line="100" selection-end-column="21" />
498   - </state>
499   - </provider>
500   - </entry>
501   - <entry file="file://$PROJECT_DIR$/app/models/kanjai/page_template.rb">
502   - <provider selected="true" editor-type-id="text-editor">
503   - <state relative-caret-position="1815">
504   - <caret line="121" column="28" selection-start-line="121" selection-start-column="28" selection-end-line="121" selection-end-column="28" />
505   - </state>
506   - </provider>
507   - </entry>
508   - <entry file="file://$PROJECT_DIR$/app/assets/javascripts/kanjai/admin/admin.js">
509   - <provider selected="true" editor-type-id="text-editor">
510   - <state relative-caret-position="2295">
511   - <caret line="153" column="51" selection-start-line="153" selection-start-column="27" selection-end-line="153" selection-end-column="51" />
512   - </state>
513   - </provider>
514   - </entry>
515   - <entry file="file://$PROJECT_DIR$/.ruby-version">
516   - <provider selected="true" editor-type-id="text-editor">
517   - <state>
518   - <caret column="5" selection-end-column="5" />
519   - </state>
520   - </provider>
521   - </entry>
522   - <entry file="file://$PROJECT_DIR$/config/initializers/aws.rb">
523   - <provider selected="true" editor-type-id="text-editor">
524   - <state relative-caret-position="75">
525   - <caret line="5" column="57" selection-start-line="5" selection-start-column="41" selection-end-line="5" selection-end-column="57" />
526   - </state>
527   - </provider>
528   - </entry>
529   - <entry file="file://$PROJECT_DIR$/lib/kanjai/template_generator.rb">
530   - <provider selected="true" editor-type-id="text-editor">
531   - <state relative-caret-position="3390">
532   - <caret line="226" column="42" selection-start-line="226" selection-start-column="23" selection-end-line="226" selection-end-column="42" />
533   - </state>
534   - </provider>
535   - </entry>
536   - <entry file="file://$PROJECT_DIR$/app/controllers/kanjai/pages_controller.rb">
537   - <provider selected="true" editor-type-id="text-editor">
538   - <state relative-caret-position="465">
539   - <caret line="31" selection-start-line="31" selection-end-line="31" />
540   - </state>
541   - </provider>
542   - </entry>
543   - <entry file="file://$PROJECT_DIR$/Gemfile.lock">
544   - <provider selected="true" editor-type-id="text-editor">
545   - <state relative-caret-position="795">
546   - <caret line="53" column="13" selection-start-line="53" selection-start-column="13" selection-end-line="53" selection-end-column="13" />
547   - </state>
548   - </provider>
549   - </entry>
550   - <entry file="file://$PROJECT_DIR$/config/initializers/devise.rb">
551   - <provider selected="true" editor-type-id="text-editor">
552   - <state relative-caret-position="90">
553   - <caret line="6" column="46" selection-start-line="6" selection-start-column="22" selection-end-line="6" selection-end-column="46" />
554   - </state>
555   - </provider>
556   - </entry>
557   - <entry file="file://$PROJECT_DIR$/config/initializers/admin.rb">
558   - <provider selected="true" editor-type-id="text-editor">
559   - <state relative-caret-position="45">
560   - <caret line="3" column="46" selection-start-line="3" selection-start-column="46" selection-end-line="3" selection-end-column="46" />
561   - </state>
562   - </provider>
563   - </entry>
564   - <entry file="file://$PROJECT_DIR$/lib/kanjai.rb">
565   - <provider selected="true" editor-type-id="text-editor" />
566   - </entry>
567   - <entry file="file://$PROJECT_DIR$/lib/kanjai/engine.rb">
568   - <provider selected="true" editor-type-id="text-editor" />
569   - </entry>
570   - <entry file="file://$PROJECT_DIR$/db/migrate/20160707115443_add_show_public_only_to_kanjai_pages.rb">
571   - <provider selected="true" editor-type-id="text-editor">
572   - <state relative-caret-position="30">
573   - <caret line="2" column="73" selection-start-line="2" selection-start-column="4" selection-end-line="2" selection-end-column="73" />
574   - </state>
575   - </provider>
576   - </entry>
577   - <entry file="file://$PROJECT_DIR$/lib/kanjai/version.rb">
578   - <provider selected="true" editor-type-id="text-editor">
579   - <state relative-caret-position="45">
580   - <caret line="3" selection-start-line="3" selection-end-line="3" />
581   - </state>
582   - </provider>
583   - </entry>
584   - </component>
585   -</project>
\ No newline at end of file
... ... @@ -2,6 +2,7 @@ PATH
2 2 remote: .
3 3 specs:
4 4 kanjai (0.0.140)
  5 + acts-as-taggable-on (~> 6.5)
5 6 acts_as_list
6 7 acts_as_tree
7 8 aws-sdk
... ... @@ -55,8 +56,10 @@ GEM
55 56 i18n (>= 0.7, < 2)
56 57 minitest (~> 5.1)
57 58 tzinfo (~> 1.1)
58   - acts_as_list (0.9.19)
59   - activerecord (>= 3.0)
  59 + acts-as-taggable-on (6.5.0)
  60 + activerecord (>= 5.0, < 6.1)
  61 + acts_as_list (1.0.1)
  62 + activerecord (>= 4.2)
60 63 acts_as_tree (2.9.1)
61 64 activerecord (>= 3.0.0)
62 65 arel (9.0.0)
... ... @@ -1019,16 +1022,16 @@ GEM
1019 1022 rb-fsevent (0.10.3)
1020 1023 rb-inotify (0.10.1)
1021 1024 ffi (~> 1.0)
1022   - responders (2.4.1)
1023   - actionpack (>= 4.2.0, < 6.0)
1024   - railties (>= 4.2.0, < 6.0)
  1025 + responders (3.0.0)
  1026 + actionpack (>= 5.0)
  1027 + railties (>= 5.0)
1025 1028 sass (3.7.4)
1026 1029 sass-listen (~> 4.0.0)
1027 1030 sass-listen (4.0.0)
1028 1031 rb-fsevent (~> 0.9, >= 0.9.4)
1029 1032 rb-inotify (~> 0.9, >= 0.9.7)
1030   - sass-rails (5.0.7)
1031   - railties (>= 4.0.0, < 6)
  1033 + sass-rails (5.1.0)
  1034 + railties (>= 5.2.0)
1032 1035 sass (~> 3.1)
1033 1036 sprockets (>= 2.8, < 4.0)
1034 1037 sprockets-rails (>= 2.0, < 4.0)
... ... @@ -1060,4 +1063,4 @@ DEPENDENCIES
1060 1063 kanjai!
1061 1064
1062 1065 BUNDLED WITH
1063   - 2.0.1
  1066 + 2.1.4
... ...
... ... @@ -14,8 +14,8 @@ RDoc::Task.new(:rdoc) do |rdoc|
14 14 rdoc.rdoc_files.include('lib/**/*.rb')
15 15 end
16 16
17   -APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
18   -load 'rails/tasks/engine.rake'
  17 +#APP_RAKEFILE = File.expand_path("../Rakefile", __FILE__)
  18 +#load 'rails/tasks/engine.rake'
19 19
20 20
21 21 load 'rails/tasks/statistics.rake'
... ...
... ... @@ -1389,40 +1389,31 @@ var add_fields = function(target, association, content){
1389 1389 jQuery(target).append(content.replace(regexp, new_id));
1390 1390 };
1391 1391
1392   -
1393   -
1394   -
1395   -var initAjaxFileUpload = function(selector){
1396   -
1397   -
1398   - function send_ajax_form($form){
1399   - $('#progress-window').find('.modal-body').append('<div>Upload form data, please wait...</div>');
1400   - var url = $form.attr('action');
1401   -
1402   - if($form.hasClass('simple_submit')){
  1392 +function send_ajax_form($form){
  1393 + $('#progress-window').find('.modal-body').append('<div>Upload form data, please wait...</div>');
  1394 + var url = $form.attr('action');
  1395 +
  1396 + if($form.hasClass('simple_submit')){
  1397 + $('#progress-window').modal('hide');
  1398 + $('#progress-window').remove();
  1399 + $form.removeClass('ajax-file-upload-form');
  1400 + //$form.unbind('submit', addFileForAjaxUpload);
  1401 + $form.unbind('submit');
  1402 + $form.submit();
  1403 +
  1404 + }else{
  1405 + $.post(url, $form.serialize(), function(){
1403 1406 $('#progress-window').modal('hide');
1404 1407 $('#progress-window').remove();
1405   - $form.removeClass('ajax-file-upload-form');
1406   - //$form.unbind('submit', addFileForAjaxUpload);
1407   - $form.unbind('submit', addFileForAjaxUpload);
1408   - $form.submit();
1409   -
1410   - }else{
1411   - $.post(url, $form.serialize(), function(){
1412   - $('#progress-window').modal('hide');
1413   - $('#progress-window').remove();
1414   - });
1415   - }
  1408 + $(window).trigger('images:update');
  1409 + });
1416 1410 }
  1411 +}
1417 1412
1418 1413
1419   -
1420   - var addFileForAjaxUpload = function(e){
1421   - var $form = $(this),
1422   - count_files = 0,
  1414 +var addFileForAjaxUpload = function(selector, $form){
  1415 + var count_files = 0,
1423 1416 count_upload = 0;
1424   - e.preventDefault();
1425   - e.stopPropagation();
1426 1417
1427 1418 selector.find(".ajax-file-upload-form input:file").each(function(){
1428 1419 var $this = $(this),
... ... @@ -1454,7 +1445,7 @@ var initAjaxFileUpload = function(selector){
1454 1445
1455 1446
1456 1447 $this.fileupload('send', {files: fileToSend})
1457   - .complete(function (result, textStatus, jqXHR) {
  1448 + .done(function (result, textStatus, jqXHR) {
1458 1449 count_upload = count_upload + 1;
1459 1450 if(count_upload == count_files){
1460 1451 send_ajax_form($form);
... ... @@ -1472,7 +1463,11 @@ var initAjaxFileUpload = function(selector){
1472 1463
1473 1464
1474 1465
1475   - }
  1466 +}
  1467 +
  1468 +
  1469 +var initAjaxFileUpload = function(selector){
  1470 +
1476 1471
1477 1472 var initFileInput = function(fileInputElem){
1478 1473 var form = $(fileInputElem.parents('form:first'));
... ... @@ -1499,7 +1494,6 @@ var initAjaxFileUpload = function(selector){
1499 1494 },
1500 1495 progressall: function (e, data) {
1501 1496 var progress = parseInt(data.loaded / data.total * 100, 10);
1502   -
1503 1497 $('.' + class_name).find('.progress-bar').css('width', progress + '%');
1504 1498 },
1505 1499 start: function (e) {
... ... @@ -1513,7 +1507,6 @@ var initAjaxFileUpload = function(selector){
1513 1507
1514 1508 $('.' + class_name).find('.progress-bar').addClass('progress-bar-success');
1515 1509
1516   -
1517 1510 // extract key and generate URL from response
1518 1511 var key = $(data.jqXHR.responseXML).find("Key").text();
1519 1512 var url = 'https://' + fileInputElem.data('host') + '/' + key;
... ... @@ -1542,7 +1535,12 @@ var initAjaxFileUpload = function(selector){
1542 1535
1543 1536
1544 1537
1545   - selector.find('.ajax-file-upload-form').submit(addFileForAjaxUpload);
  1538 + selector.find('.ajax-file-upload-form').submit(function(e){
  1539 + e.preventDefault();
  1540 + e.stopPropagation();
  1541 +
  1542 + addFileForAjaxUpload(selector, $(this))
  1543 + });
1546 1544
1547 1545 $(document).bind('drop dragover', function (e) {
1548 1546 e.preventDefault();
... ... @@ -1552,10 +1550,23 @@ var initAjaxFileUpload = function(selector){
1552 1550 };
1553 1551
1554 1552 var clearAjaxFileUpload = function(selector){
1555   - selector.find('.ajax-file-upload-form').unbind('submit', addFileForAjaxUpload);
  1553 + selector.find('.ajax-file-upload-form').unbind('submit');
1556 1554 };
1557 1555
1558 1556
  1557 +var tagnames = new Bloodhound({
  1558 + datumTokenizer: Bloodhound.tokenizers.obj.whitespace('title'),
  1559 + queryTokenizer: Bloodhound.tokenizers.whitespace,
  1560 + prefetch: {
  1561 + url: '/admin/tags',
  1562 + filter: function(list) {
  1563 + return $.map(list, function(title) {
  1564 + return { title: title }; });
  1565 + }
  1566 + }
  1567 +});
  1568 +tagnames.initialize();
  1569 +
1559 1570
1560 1571 jQuery(document).ready(function(){
1561 1572
... ... @@ -1724,46 +1735,78 @@ jQuery(document).ready(function(){
1724 1735 }else {
1725 1736 dropZone[0].ondrop = function (e) {
1726 1737 e.preventDefault();
1727   - var file = e.dataTransfer.files[0],
1728   - input_name = "gallery_image[" + file_index + "]",
1729   - $fileInput = $('<div><input name="' + input_name + '" type="file" class="fileupload-field"></div>');
  1738 + $.each(e.dataTransfer.files, function(){
  1739 + var file = this,
  1740 + input_name = "gallery_image[" + file_index + "]",
  1741 + $fileInput = $('<div><input name="' + input_name + 'file" type="file" class="fileupload-field"></div>');
1730 1742
1731   - file_index = file_index + 1;
  1743 + file_index = file_index + 1;
1732 1744
1733   - $fileInput.find('.fileupload-field').data('url', upload_url);
1734   - $fileInput.find('.fileupload-field').data('form-data', upload_form_data);
1735   - $fileInput.find('.fileupload-field').data('host', upload_host);
  1745 + $fileInput.find('.fileupload-field').data('url', upload_url);
  1746 + $fileInput.find('.fileupload-field').data('form-data', upload_form_data);
  1747 + $fileInput.find('.fileupload-field').data('host', upload_host);
1736 1748
1737 1749
1738   - $fileInput.find('.fileupload-field').data('files', [{input_name: input_name, file: file}]);
  1750 + $fileInput.find('.fileupload-field').data('files', [{input_name: input_name + 'file', file: file}]);
1739 1751
1740   - var reader = new FileReader();
1741   - reader.onload = function (evt) {
1742   - var options = {
1743   - showUpload:false,
1744   - dropZoneEnabled: false,
1745   - initialPreview: ["<img src='"+ evt.target.result +"' class='file-preview-image' alt='' title=''>"]
1746   - };
  1752 + var reader = new FileReader();
  1753 + reader.onload = function (evt) {
  1754 + var options = {
  1755 + showUpload:false,
  1756 + dropZoneEnabled: false,
  1757 + contentType: true,
  1758 + initialPreview: ["<img src='"+ evt.target.result +"' class='file-preview-image' alt='' title=''>"]
  1759 + };
1747 1760
1748   - $fileInput.find('.fileupload-field').fileinput(options);
  1761 + $fileInput.find('.fileupload-field').fileinput(options);
1749 1762
1750   - $fileInput.find('.fileupload-field').on('fileclear', function(event) {
1751   - $(this).closest('.file-input').remove();
1752   - });
  1763 + $fileInput.find('.fileupload-field').on('fileclear', function(event) {
  1764 + if($(this).closest('.new-image-wrapper').length > 0){
  1765 + $(this).closest('.new-image-wrapper').remove();
  1766 + }else{
  1767 + $(this).closest('.file-input').remove();
  1768 + }
  1769 + });
1753 1770
1754   - $fileInput.find('.fileupload-field').on('change', function(event) {
  1771 + $fileInput.find('.fileupload-field').on('change', function(event) {
1755 1772
1756   - });
  1773 + });
  1774 + if($('#gallery_form form').find('.add-new-field').length > 0){
  1775 + var template = $('#gallery_form form').find('.add-new-field').data('template');
  1776 + template = template.replace(/\{name\}/g, input_name);
  1777 + var $template = $(template);
  1778 + $template.find('.fileupload-preview').html($fileInput);
  1779 + $template.find('.file-type').val(file.type);
  1780 +
  1781 + $template.find('.remove').click(function(){
  1782 + $(this).closest('.new-image-wrapper').find('.fileinput-remove').trigger('click');
  1783 + return false;
  1784 + });
  1785 + $('#gallery_form form #new_images').append($template);
  1786 +
  1787 +
  1788 +
  1789 + $template.find("input[data-role=tagsinput]").tagsinput({
  1790 + typeaheadjs: {
  1791 + name: 'title',
  1792 + displayKey: 'title',
  1793 + valueKey: 'title',
  1794 + source: tagnames.ttAdapter()
  1795 + }
  1796 + });
  1797 + }else{
  1798 + $('#gallery_form form #new_images').append($fileInput);
  1799 + }
1757 1800
1758   - $('#gallery_form form #new_images').append($fileInput);
  1801 + $('#gallery_form form input:submit').removeClass('not-visible');
1759 1802
1760   - $('#gallery_form form input:submit').removeClass('not-visible');
  1803 + clearAjaxFileUpload($('#gallery_form'));
  1804 + initAjaxFileUpload($('#gallery_form'));
1761 1805
1762   - clearAjaxFileUpload($('#gallery_form'));
1763   - initAjaxFileUpload($('#gallery_form'));
  1806 + };
  1807 + reader.readAsDataURL(file);
  1808 + });
1764 1809
1765   - };
1766   - reader.readAsDataURL(file);
1767 1810
1768 1811
1769 1812
... ... @@ -1837,6 +1880,7 @@ jQuery(document).ready(function(){
1837 1880 });
1838 1881 });
1839 1882
  1883 +
1840 1884 $('.dropdown-toggle').dropdown();
1841 1885
1842 1886 });
... ...
  1 +/*
  2 + * bootstrap-filestyle
  3 + * doc: http://markusslima.github.io/bootstrap-filestyle/
  4 + * github: https://github.com/markusslima/bootstrap-filestyle
  5 + *
  6 + * Copyright (c) 2017 Markus Vinicius da Silva Lima
  7 + * Version 2.1.0
  8 + * Licensed under the MIT license.
  9 + */
  10 +(function($) {
  11 + "use strict";
  12 +
  13 + var nextId = 0;
  14 +
  15 + var Filestyle = function(element, options) {
  16 + this.options = options;
  17 + this.$elementFilestyle = [];
  18 + this.$element = $(element);
  19 + };
  20 +
  21 + Filestyle.prototype = {
  22 + clear : function() {
  23 + this.$element.val('');
  24 + this.$elementFilestyle.find(':text').val('');
  25 + this.$elementFilestyle.find('.badge').remove();
  26 + },
  27 +
  28 + destroy : function() {
  29 + this.$element.removeAttr('style').removeData('filestyle');
  30 + this.$elementFilestyle.remove();
  31 + },
  32 +
  33 + disabled : function(value) {
  34 + if (value === true || value === false) {
  35 + this.options.disabled = value;
  36 + this.$element.prop('disabled', this.options.disabled);
  37 + this.$elementFilestyle.find('label').prop('disabled', this.options.disabled);
  38 +
  39 + if (this.options.disabled)
  40 + this.$elementFilestyle.find('label').css('opacity', '0.65');
  41 + else
  42 + this.$elementFilestyle.find('label').css('opacity', '1');
  43 + } else {
  44 + return this.options.disabled;
  45 + }
  46 + },
  47 +
  48 + dragdrop : function(value) {
  49 + if (value === true || value === false) {
  50 + this.options.dragdrop = value;
  51 + } else {
  52 + return this.options.dragdrop;
  53 + }
  54 + },
  55 +
  56 + buttonBefore : function(value) {
  57 + if (value === true) {
  58 + if (!this.options.buttonBefore) {
  59 + this.options.buttonBefore = value;
  60 + if (this.options.input) {
  61 + this.$elementFilestyle.remove();
  62 + this.constructor();
  63 + this.pushNameFiles();
  64 + }
  65 + }
  66 + } else if (value === false) {
  67 + if (this.options.buttonBefore) {
  68 + this.options.buttonBefore = value;
  69 + if (this.options.input) {
  70 + this.$elementFilestyle.remove();
  71 + this.constructor();
  72 + this.pushNameFiles();
  73 + }
  74 + }
  75 + } else {
  76 + return this.options.buttonBefore;
  77 + }
  78 + },
  79 +
  80 + input : function(value) {
  81 + if (value === true) {
  82 + if (!this.options.input) {
  83 + this.options.input = value;
  84 +
  85 + if (this.options.buttonBefore) {
  86 + this.$elementFilestyle.append(this.htmlInput());
  87 + } else {
  88 + this.$elementFilestyle.prepend(this.htmlInput());
  89 + }
  90 +
  91 + this.pushNameFiles();
  92 + this.$elementFilestyle.find('.group-span-filestyle').addClass('input-group-btn');
  93 + }
  94 + } else if (value === false) {
  95 + if (this.options.input) {
  96 + this.options.input = value;
  97 + this.$elementFilestyle.find(':text').remove();
  98 + this.$elementFilestyle.find('.group-span-filestyle').removeClass('input-group-btn');
  99 + }
  100 + } else {
  101 + return this.options.input;
  102 + }
  103 + },
  104 +
  105 + size : function(value) {
  106 + if (value !== undefined) {
  107 + this.options.size = value;
  108 + var btn = this.$elementFilestyle.find('label'), input = this.$elementFilestyle.find('input');
  109 +
  110 + btn.removeClass('btn-lg btn-sm');
  111 + input.removeClass('form-control-lg form-control-sm');
  112 + if (this.options.size != 'nr') {
  113 + btn.addClass('btn-' + this.options.size);
  114 + input.addClass('form-control-' + this.options.size);
  115 + }
  116 + } else {
  117 + return this.options.size;
  118 + }
  119 + },
  120 +
  121 + placeholder : function(value) {
  122 + if (value !== undefined) {
  123 + this.options.placeholder = value;
  124 + this.$elementFilestyle.find('input').attr('placeholder', value);
  125 + } else {
  126 + return this.options.placeholder;
  127 + }
  128 + },
  129 +
  130 + text : function(value) {
  131 + if (value !== undefined) {
  132 + this.options.text = value;
  133 + this.$elementFilestyle.find('label .text').html(this.options.text);
  134 + } else {
  135 + return this.options.text;
  136 + }
  137 + },
  138 +
  139 + btnClass : function(value) {
  140 + if (value !== undefined) {
  141 + this.options.btnClass = value;
  142 + this.$elementFilestyle.find('label').attr({
  143 + 'class' : 'btn ' + this.options.btnClass + ' btn-' + this.options.size
  144 + });
  145 + } else {
  146 + return this.options.btnClass;
  147 + }
  148 + },
  149 +
  150 + badge : function(value) {
  151 + if (value === true) {
  152 + this.options.badge = value;
  153 + var files = this.pushNameFiles();
  154 + this.$elementFilestyle.find('label').append(' <span class="badge '+this.options.badgeName+'">' + files.length + '</span>');
  155 + } else if (value === false) {
  156 + this.options.badge = value;
  157 + this.$elementFilestyle.find('.badge').remove();
  158 + } else {
  159 + return this.options.badge;
  160 + }
  161 + },
  162 +
  163 + badgeName : function(value) {
  164 + if (value !== undefined) {
  165 + this.options.badgeName = value;
  166 + this.$elementFilestyle.find('.badge').attr({
  167 + 'class' : 'badge ' + this.options.badgeName
  168 + });
  169 + } else {
  170 + return this.options.badgeName;
  171 + }
  172 + },
  173 +
  174 + htmlIcon : function(value) {
  175 + if (value !== undefined) {
  176 + this.options.htmlIcon = value;
  177 + }
  178 +
  179 + return this.options.htmlIcon;
  180 + },
  181 +
  182 + htmlInput : function() {
  183 + if (this.options.input) {
  184 + return '<input type="text" class="form-control ' + (this.options.size == 'nr' ? '' : 'form-control-' + this.options.size) + '" placeholder="'+ this.options.placeholder +'" disabled> ';
  185 + } else {
  186 + return '';
  187 + }
  188 + },
  189 +
  190 + // puts the name of the input files
  191 + // return files
  192 + pushNameFiles : function() {
  193 + var content = '', files = [];
  194 + if (this.$element[0].files === undefined) {
  195 + files[0] = {
  196 + 'name' : this.$element[0] && this.$element[0].value
  197 + };
  198 + } else {
  199 + files = this.$element[0].files;
  200 + }
  201 +
  202 + for (var i = 0; i < files.length; i++) {
  203 + content += files[i].name.split("\\").pop() + ', ';
  204 + }
  205 +
  206 + if (content !== '') {
  207 + this.$elementFilestyle.find(':text').val(content.replace(/\, $/g, ''));
  208 + } else {
  209 + this.$elementFilestyle.find(':text').val('');
  210 + }
  211 +
  212 + return files;
  213 + },
  214 +
  215 + constructor : function() {
  216 + var _self = this,
  217 + html = '',
  218 + id = _self.$element.attr('id'),
  219 + files = [],
  220 + btn = '',
  221 + $label;
  222 +
  223 + if (id === '' || !id) {
  224 + id = 'filestyle-' + nextId;
  225 + _self.$element.attr({
  226 + 'id' : id
  227 + });
  228 + nextId++;
  229 + }
  230 +
  231 + btn = '<span class="group-span-filestyle ' + (_self.options.input ? 'input-group-btn' : '') + '">' +
  232 + '<label for="' + id + '" style="margin-bottom: 0;" class="btn ' + _self.options.btnClass + ' ' +
  233 + (_self.options.size == 'nr' ? '' : 'btn-' + _self.options.size) + '" ' +
  234 + (_self.options.disabled || _self.$element.attr('disabled') ? ' disabled="true"' : '') + '>' +
  235 + _self.htmlIcon() + '<span class="buttonText">' + _self.options.text + '</span>' +
  236 + '</label>' +
  237 + '</span>';
  238 +
  239 + html = _self.options.buttonBefore ? btn + _self.htmlInput() : _self.htmlInput() + btn;
  240 + _self.$elementFilestyle = $('<div class="bootstrap-filestyle input-group"><div name="filedrag"></div>' + html + '</div>');
  241 + _self.$elementFilestyle.find('.group-span-filestyle').attr('tabindex', "0").keypress(function(e) {
  242 + if (e.keyCode === 13 || e.charCode === 32) {
  243 + _self.$elementFilestyle.find('label').click();
  244 + return false;
  245 + }
  246 + });
  247 +
  248 + // hidding input file and add filestyle
  249 + _self.$element.css({
  250 + 'position' : 'absolute',
  251 + 'clip' : 'rect(0px 0px 0px 0px)' // using 0px for work in IE8
  252 + }).attr('tabindex', "-1").after(_self.$elementFilestyle);
  253 +
  254 + _self.$elementFilestyle.find(_self.options.buttonBefore ? 'label' : ':input').css({
  255 + 'border-top-left-radius': '.25rem',
  256 + 'border-bottom-left-radius': '.25rem'
  257 + });
  258 +
  259 + _self.$elementFilestyle.find('[name="filedrag"]').css({
  260 + position: 'absolute',
  261 + width: '100%',
  262 + height: _self.$elementFilestyle.height()+'px',
  263 + 'z-index': -1
  264 + });
  265 +
  266 + if (_self.options.disabled || _self.$element.attr('disabled')) {
  267 + _self.$element.attr('disabled', 'true');
  268 + if (_self.options.disabled)
  269 + _self.$elementFilestyle.find('label').css('opacity', '0.65');
  270 + else
  271 + _self.$elementFilestyle.find('label').css('opacity', '1');
  272 + }
  273 +
  274 + // Getting input file value
  275 + _self.$element.change(function () {
  276 + var files = _self.pushNameFiles();
  277 + if (_self.options.badge) {
  278 + if (_self.$elementFilestyle.find('.badge').length == 0) {
  279 + _self.$elementFilestyle.find('label').append(' <span class="badge '+_self.options.badgeName+'">' + files.length + '</span>');
  280 + } else if (files.length == 0) {
  281 + _self.$elementFilestyle.find('.badge').remove();
  282 + } else {
  283 + _self.$elementFilestyle.find('.badge').html(files.length);
  284 + }
  285 + } else {
  286 + _self.$elementFilestyle.find('.badge').remove();
  287 + }
  288 +
  289 + _self.options.onChange(files);
  290 + });
  291 +
  292 + // Check if browser is Firefox
  293 + if (window.navigator.userAgent.search(/firefox/i) > -1) {
  294 + // Simulating choose file for firefox
  295 + _self.$elementFilestyle.find('label').click(function() {
  296 + _self.$element.click();
  297 + return false;
  298 + });
  299 + }
  300 +
  301 + /** DRAG AND DROP EVENTS **/
  302 + $(document)
  303 + .on('dragover', function (e) {
  304 + e.preventDefault();
  305 + e.stopPropagation();
  306 + if (_self.options.dragdrop) {
  307 + $('[name="filedrag"]').css('z-index', '9');
  308 + }
  309 + })
  310 + .on('drop', function (e) {
  311 + e.preventDefault();
  312 + e.stopPropagation();
  313 + if (_self.options.dragdrop) {
  314 + $('[name="filedrag"]').css('z-index', '-1');
  315 + }
  316 + });
  317 +
  318 + _self.$elementFilestyle.find('[name="filedrag"]')
  319 + .on('dragover',
  320 + function (e) {
  321 + e.preventDefault();
  322 + e.stopPropagation();
  323 + }
  324 + )
  325 + .on('dragenter',
  326 + function (e) {
  327 + e.preventDefault();
  328 + e.stopPropagation();
  329 + }
  330 + )
  331 + .on('drop',
  332 + function (e) {
  333 + if (e.originalEvent.dataTransfer && !_self.options.disabled && _self.options.dragdrop) {
  334 + if (e.originalEvent.dataTransfer.files.length) {
  335 + e.preventDefault();
  336 + e.stopPropagation();
  337 + _self.$element[0].files = e.originalEvent.dataTransfer.files;
  338 + var files = _self.pushNameFiles();
  339 + if (_self.options.badge) {
  340 + if (_self.$elementFilestyle.find('.badge').length == 0) {
  341 + _self.$elementFilestyle.find('label').append(' <span class="badge '+_self.options.badgeName+'">' + files.length + '</span>');
  342 + } else if (files.length == 0) {
  343 + _self.$elementFilestyle.find('.badge').remove();
  344 + } else {
  345 + _self.$elementFilestyle.find('.badge').html(files.length);
  346 + }
  347 + } else {
  348 + _self.$elementFilestyle.find('.badge').remove();
  349 + }
  350 +
  351 + $('[name="filedrag"]').css('z-index', '-1');
  352 + }
  353 + }
  354 + }
  355 + );
  356 + }
  357 + };
  358 +
  359 + var old = $.fn.filestyle;
  360 +
  361 + $.fn.filestyle = function(option, value) {
  362 + var get = '', element = this.each(function() {
  363 + if ($(this).attr('type') === 'file') {
  364 + var $this = $(this), data = $this.data('filestyle'), options = $.extend({}, $.fn.filestyle.defaults, option, typeof option === 'object' && option);
  365 +
  366 + if (!data) {
  367 + $this.data('filestyle', ( data = new Filestyle(this, options)));
  368 + data.constructor();
  369 + }
  370 +
  371 + if ( typeof option === 'string') {
  372 + get = data[option](value);
  373 + }
  374 + }
  375 + });
  376 +
  377 + if ( typeof get !== undefined) {
  378 + return get;
  379 + } else {
  380 + return element;
  381 + }
  382 + };
  383 +
  384 + $.fn.filestyle.defaults = {
  385 + 'text' : 'Choose file',
  386 + 'htmlIcon' : '',
  387 + 'btnClass' : 'btn-secondary',
  388 + 'size' : 'nr',
  389 + 'input' : true,
  390 + 'badge' : false,
  391 + 'badgeName': 'badge-light',
  392 + 'buttonBefore' : false,
  393 + 'dragdrop' : true,
  394 + 'disabled' : false,
  395 + 'placeholder': '',
  396 + 'onChange': function () {}
  397 + };
  398 +
  399 + $.fn.filestyle.noConflict = function() {
  400 + $.fn.filestyle = old;
  401 + return this;
  402 + };
  403 +
  404 + $(function() {
  405 + $('.filestyle').each(function() {
  406 + var $this = $(this), options = {
  407 + 'input' : $this.attr('data-input') !== 'false',
  408 + 'htmlIcon' : $this.attr('data-icon'),
  409 + 'buttonBefore' : $this.attr('data-buttonBefore') === 'true',
  410 + 'disabled' : $this.attr('data-disabled') === 'true',
  411 + 'size' : $this.attr('data-size'),
  412 + 'text' : $this.attr('data-text'),
  413 + 'btnClass' : $this.attr('data-btnClass'),
  414 + 'badge' : $this.attr('data-badge') === 'true',
  415 + 'dragdrop' : $this.attr('data-dragdrop') !== 'false',
  416 + 'badgeName' : $this.attr('data-badgeName'),
  417 + 'placeholder': $this.attr('data-placeholder')
  418 + };
  419 +
  420 + $this.filestyle(options);
  421 + });
  422 + });
  423 +})(window.jQuery);
\ No newline at end of file
... ...
... ... @@ -455,6 +455,7 @@
455 455 options.headers['Content-Disposition'] = 'attachment; filename="' +
456 456 encodeURI(file.name) + '"';
457 457 }
  458 +
458 459 if (!multipart) {
459 460 options.contentType = file.type || 'application/octet-stream';
460 461 options.data = options.blob || file;
... ...
  1 +jQuery(document).ready(function(){
  2 + var loadImage = function($wrapper){
  3 + var url = $wrapper.data('url'),
  4 + $loader = $wrapper.find('.loader-demo'),
  5 + $images = $wrapper.find('.exist-image-list');
  6 +
  7 + $loader.removeClass('not-visible');
  8 + $images.addClass('not-visible');
  9 +
  10 + var mas = [];
  11 + $wrapper.find('.filter label.active').each(function(){
  12 + mas.push($(this).data('value'));
  13 + });
  14 +
  15 + jQuery.ajax({
  16 + type: 'POST',
  17 + url: url,
  18 + data: ({tags: mas}),
  19 + dataType: 'html',
  20 + success: function(data){
  21 + $images.html(data);
  22 + $loader.addClass('not-visible');
  23 + $images.removeClass('not-visible');
  24 + }
  25 + });
  26 + };
  27 +
  28 + if($('.image-list').length > 0){
  29 + var $wrapper = $('.image-list');
  30 + loadImage($wrapper);
  31 + $wrapper.find('.filter label').click(function(){
  32 + var $this = $(this);
  33 + if($this.hasClass('active')){
  34 + $this.removeClass('active');
  35 + }else{
  36 + $this.addClass('active');
  37 + }
  38 + if($this.data('value') == 'all' && $this.hasClass('active')){
  39 + $wrapper.find(".filter label.active").not($this).removeClass('active');
  40 + };
  41 + if($this.data('value') != 'all' && $this.hasClass('active')){
  42 + $wrapper.find(".filter label.active[data-value=all]").removeClass('active');
  43 + };
  44 + loadImage($wrapper);
  45 + });
  46 + }
  47 +
  48 + $(window).bind('images:update', function(){
  49 + if($('.image-list').length > 0){
  50 + loadImage($('.image-list'));
  51 + };
  52 + });
  53 +});
\ No newline at end of file
... ...
  1 +(function ($) {
  2 + "use strict";
  3 +
  4 + var defaultOptions = {
  5 + tagClass: function(item) {
  6 + return 'label label-info';
  7 + },
  8 + itemValue: function(item) {
  9 + return item ? item.toString() : item;
  10 + },
  11 + itemText: function(item) {
  12 + return this.itemValue(item);
  13 + },
  14 + itemTitle: function(item) {
  15 + return null;
  16 + },
  17 + freeInput: true,
  18 + addOnBlur: true,
  19 + maxTags: undefined,
  20 + maxChars: undefined,
  21 + confirmKeys: [13, 44],
  22 + delimiter: ',',
  23 + delimiterRegex: null,
  24 + cancelConfirmKeysOnEmpty: true,
  25 + onTagExists: function(item, $tag) {
  26 + $tag.hide().fadeIn();
  27 + },
  28 + trimValue: false,
  29 + allowDuplicates: false
  30 + };
  31 +
  32 + /**
  33 + * Constructor function
  34 + */
  35 + function TagsInput(element, options) {
  36 + this.itemsArray = [];
  37 +
  38 + this.$element = $(element);
  39 + this.$element.hide();
  40 +
  41 + this.isSelect = (element.tagName === 'SELECT');
  42 + this.multiple = (this.isSelect && element.hasAttribute('multiple'));
  43 + this.objectItems = options && options.itemValue;
  44 + this.placeholderText = element.hasAttribute('placeholder') ? this.$element.attr('placeholder') : '';
  45 + this.inputSize = Math.max(1, this.placeholderText.length);
  46 +
  47 + this.$container = $('<div class="bootstrap-tagsinput"></div>');
  48 + this.$input = $('<input type="text" placeholder="' + this.placeholderText + '"/>').appendTo(this.$container);
  49 +
  50 + this.$element.before(this.$container);
  51 +
  52 + this.build(options);
  53 + }
  54 +
  55 + TagsInput.prototype = {
  56 + constructor: TagsInput,
  57 +
  58 + /**
  59 + * Adds the given item as a new tag. Pass true to dontPushVal to prevent
  60 + * updating the elements val()
  61 + */
  62 + add: function(item, dontPushVal, options) {
  63 + var self = this;
  64 +
  65 + if (self.options.maxTags && self.itemsArray.length >= self.options.maxTags)
  66 + return;
  67 +
  68 + // Ignore falsey values, except false
  69 + if (item !== false && !item)
  70 + return;
  71 +
  72 + // Trim value
  73 + if (typeof item === "string" && self.options.trimValue) {
  74 + item = $.trim(item);
  75 + }
  76 +
  77 + // Throw an error when trying to add an object while the itemValue option was not set
  78 + if (typeof item === "object" && !self.objectItems)
  79 + throw("Can't add objects when itemValue option is not set");
  80 +
  81 + // Ignore strings only containg whitespace
  82 + if (item.toString().match(/^\s*$/))
  83 + return;
  84 +
  85 + // If SELECT but not multiple, remove current tag
  86 + if (self.isSelect && !self.multiple && self.itemsArray.length > 0)
  87 + self.remove(self.itemsArray[0]);
  88 +
  89 + if (typeof item === "string" && this.$element[0].tagName === 'INPUT') {
  90 + var delimiter = (self.options.delimiterRegex) ? self.options.delimiterRegex : self.options.delimiter;
  91 + var items = item.split(delimiter);
  92 + if (items.length > 1) {
  93 + for (var i = 0; i < items.length; i++) {
  94 + this.add(items[i], true);
  95 + }
  96 +
  97 + if (!dontPushVal)
  98 + self.pushVal();
  99 + return;
  100 + }
  101 + }
  102 +
  103 + var itemValue = self.options.itemValue(item),
  104 + itemText = self.options.itemText(item),
  105 + tagClass = self.options.tagClass(item),
  106 + itemTitle = self.options.itemTitle(item);
  107 +
  108 + // Ignore items allready added
  109 + var existing = $.grep(self.itemsArray, function(item) { return self.options.itemValue(item) === itemValue; } )[0];
  110 + if (existing && !self.options.allowDuplicates) {
  111 + // Invoke onTagExists
  112 + if (self.options.onTagExists) {
  113 + var $existingTag = $(".tag", self.$container).filter(function() { return $(this).data("item") === existing; });
  114 + self.options.onTagExists(item, $existingTag);
  115 + }
  116 + return;
  117 + }
  118 +
  119 + // if length greater than limit
  120 + if (self.items().toString().length + item.length + 1 > self.options.maxInputLength)
  121 + return;
  122 +
  123 + // raise beforeItemAdd arg
  124 + var beforeItemAddEvent = $.Event('beforeItemAdd', { item: item, cancel: false, options: options});
  125 + self.$element.trigger(beforeItemAddEvent);
  126 + if (beforeItemAddEvent.cancel)
  127 + return;
  128 +
  129 + // register item in internal array and map
  130 + self.itemsArray.push(item);
  131 +
  132 + // add a tag element
  133 +
  134 + var $tag = $('<span class="tag ' + htmlEncode(tagClass) + (itemTitle !== null ? ('" title="' + itemTitle) : '') + '">' + htmlEncode(itemText) + '<span data-role="remove"></span></span>');
  135 + $tag.data('item', item);
  136 + self.findInputWrapper().before($tag);
  137 + $tag.after(' ');
  138 +
  139 + // add <option /> if item represents a value not present in one of the <select />'s options
  140 + if (self.isSelect && !$('option[value="' + encodeURIComponent(itemValue) + '"]',self.$element)[0]) {
  141 + var $option = $('<option selected>' + htmlEncode(itemText) + '</option>');
  142 + $option.data('item', item);
  143 + $option.attr('value', itemValue);
  144 + self.$element.append($option);
  145 + }
  146 +
  147 + if (!dontPushVal)
  148 + self.pushVal();
  149 +
  150 + // Add class when reached maxTags
  151 + if (self.options.maxTags === self.itemsArray.length || self.items().toString().length === self.options.maxInputLength)
  152 + self.$container.addClass('bootstrap-tagsinput-max');
  153 +
  154 + self.$element.trigger($.Event('itemAdded', { item: item, options: options }));
  155 + },
  156 +
  157 + /**
  158 + * Removes the given item. Pass true to dontPushVal to prevent updating the
  159 + * elements val()
  160 + */
  161 + remove: function(item, dontPushVal, options) {
  162 + var self = this;
  163 +
  164 + if (self.objectItems) {
  165 + if (typeof item === "object")
  166 + item = $.grep(self.itemsArray, function(other) { return self.options.itemValue(other) == self.options.itemValue(item); } );
  167 + else
  168 + item = $.grep(self.itemsArray, function(other) { return self.options.itemValue(other) == item; } );
  169 +
  170 + item = item[item.length-1];
  171 + }
  172 +
  173 + if (item) {
  174 + var beforeItemRemoveEvent = $.Event('beforeItemRemove', { item: item, cancel: false, options: options });
  175 + self.$element.trigger(beforeItemRemoveEvent);
  176 + if (beforeItemRemoveEvent.cancel)
  177 + return;
  178 +
  179 + $('.tag', self.$container).filter(function() { return $(this).data('item') === item; }).remove();
  180 + $('option', self.$element).filter(function() { return $(this).data('item') === item; }).remove();
  181 + if($.inArray(item, self.itemsArray) !== -1)
  182 + self.itemsArray.splice($.inArray(item, self.itemsArray), 1);
  183 + }
  184 +
  185 + if (!dontPushVal)
  186 + self.pushVal();
  187 +
  188 + // Remove class when reached maxTags
  189 + if (self.options.maxTags > self.itemsArray.length)
  190 + self.$container.removeClass('bootstrap-tagsinput-max');
  191 +
  192 + self.$element.trigger($.Event('itemRemoved', { item: item, options: options }));
  193 + },
  194 +
  195 + /**
  196 + * Removes all items
  197 + */
  198 + removeAll: function() {
  199 + var self = this;
  200 +
  201 + $('.tag', self.$container).remove();
  202 + $('option', self.$element).remove();
  203 +
  204 + while(self.itemsArray.length > 0)
  205 + self.itemsArray.pop();
  206 +
  207 + self.pushVal();
  208 + },
  209 +
  210 + /**
  211 + * Refreshes the tags so they match the text/value of their corresponding
  212 + * item.
  213 + */
  214 + refresh: function() {
  215 + var self = this;
  216 + $('.tag', self.$container).each(function() {
  217 + var $tag = $(this),
  218 + item = $tag.data('item'),
  219 + itemValue = self.options.itemValue(item),
  220 + itemText = self.options.itemText(item),
  221 + tagClass = self.options.tagClass(item);
  222 +
  223 + // Update tag's class and inner text
  224 + $tag.attr('class', null);
  225 + $tag.addClass('tag ' + htmlEncode(tagClass));
  226 + $tag.contents().filter(function() {
  227 + return this.nodeType == 3;
  228 + })[0].nodeValue = htmlEncode(itemText);
  229 +
  230 + if (self.isSelect) {
  231 + var option = $('option', self.$element).filter(function() { return $(this).data('item') === item; });
  232 + option.attr('value', itemValue);
  233 + }
  234 + });
  235 + },
  236 +
  237 + /**
  238 + * Returns the items added as tags
  239 + */
  240 + items: function() {
  241 + return this.itemsArray;
  242 + },
  243 +
  244 + /**
  245 + * Assembly value by retrieving the value of each item, and set it on the
  246 + * element.
  247 + */
  248 + pushVal: function() {
  249 + var self = this,
  250 + val = $.map(self.items(), function(item) {
  251 + return self.options.itemValue(item).toString();
  252 + });
  253 +
  254 + self.$element.val(val, true).trigger('change');
  255 + },
  256 +
  257 + /**
  258 + * Initializes the tags input behaviour on the element
  259 + */
  260 + build: function(options) {
  261 + var self = this;
  262 +
  263 + self.options = $.extend({}, defaultOptions, options);
  264 + // When itemValue is set, freeInput should always be false
  265 + if (self.objectItems)
  266 + self.options.freeInput = false;
  267 +
  268 + makeOptionItemFunction(self.options, 'itemValue');
  269 + makeOptionItemFunction(self.options, 'itemText');
  270 + makeOptionFunction(self.options, 'tagClass');
  271 +
  272 + // Typeahead Bootstrap version 2.3.2
  273 + if (self.options.typeahead) {
  274 + var typeahead = self.options.typeahead || {};
  275 +
  276 + makeOptionFunction(typeahead, 'source');
  277 +
  278 + self.$input.typeahead($.extend({}, typeahead, {
  279 + source: function (query, process) {
  280 + function processItems(items) {
  281 + var texts = [];
  282 +
  283 + for (var i = 0; i < items.length; i++) {
  284 + var text = self.options.itemText(items[i]);
  285 + map[text] = items[i];
  286 + texts.push(text);
  287 + }
  288 + process(texts);
  289 + }
  290 +
  291 + this.map = {};
  292 + var map = this.map,
  293 + data = typeahead.source(query);
  294 +
  295 + if ($.isFunction(data.success)) {
  296 + // support for Angular callbacks
  297 + data.success(processItems);
  298 + } else if ($.isFunction(data.then)) {
  299 + // support for Angular promises
  300 + data.then(processItems);
  301 + } else {
  302 + // support for functions and jquery promises
  303 + $.when(data)
  304 + .then(processItems);
  305 + }
  306 + },
  307 + updater: function (text) {
  308 + self.add(this.map[text]);
  309 + return this.map[text];
  310 + },
  311 + matcher: function (text) {
  312 + return (text.toLowerCase().indexOf(this.query.trim().toLowerCase()) !== -1);
  313 + },
  314 + sorter: function (texts) {
  315 + return texts.sort();
  316 + },
  317 + highlighter: function (text) {
  318 + var regex = new RegExp( '(' + this.query + ')', 'gi' );
  319 + return text.replace( regex, "<strong>$1</strong>" );
  320 + }
  321 + }));
  322 + }
  323 +
  324 + // typeahead.js
  325 + if (self.options.typeaheadjs) {
  326 + var typeaheadConfig = null;
  327 + var typeaheadDatasets = {};
  328 +
  329 + // Determine if main configurations were passed or simply a dataset
  330 + var typeaheadjs = self.options.typeaheadjs;
  331 + if ($.isArray(typeaheadjs)) {
  332 + typeaheadConfig = typeaheadjs[0];
  333 + typeaheadDatasets = typeaheadjs[1];
  334 + } else {
  335 + typeaheadDatasets = typeaheadjs;
  336 + }
  337 +
  338 + self.$input.typeahead(typeaheadConfig, typeaheadDatasets).on('typeahead:selected', $.proxy(function (obj, datum) {
  339 + if (typeaheadDatasets.valueKey)
  340 + self.add(datum[typeaheadDatasets.valueKey]);
  341 + else
  342 + self.add(datum);
  343 + self.$input.typeahead('val', '');
  344 + }, self));
  345 + }
  346 +
  347 + self.$container.on('click', $.proxy(function(event) {
  348 + if (! self.$element.attr('disabled')) {
  349 + self.$input.removeAttr('disabled');
  350 + }
  351 + self.$input.focus();
  352 + }, self));
  353 +
  354 + if (self.options.addOnBlur && self.options.freeInput) {
  355 + self.$input.on('focusout', $.proxy(function(event) {
  356 + // HACK: only process on focusout when no typeahead opened, to
  357 + // avoid adding the typeahead text as tag
  358 + if ($('.typeahead, .twitter-typeahead', self.$container).length === 0) {
  359 + self.add(self.$input.val());
  360 + self.$input.val('');
  361 + }
  362 + }, self));
  363 + }
  364 +
  365 +
  366 + self.$container.on('keydown', 'input', $.proxy(function(event) {
  367 + var $input = $(event.target),
  368 + $inputWrapper = self.findInputWrapper();
  369 +
  370 + if (self.$element.attr('disabled')) {
  371 + self.$input.attr('disabled', 'disabled');
  372 + return;
  373 + }
  374 +
  375 + switch (event.which) {
  376 + // BACKSPACE
  377 + case 8:
  378 + if (doGetCaretPosition($input[0]) === 0) {
  379 + var prev = $inputWrapper.prev();
  380 + if (prev.length) {
  381 + self.remove(prev.data('item'));
  382 + }
  383 + }
  384 + break;
  385 +
  386 + // DELETE
  387 + case 46:
  388 + if (doGetCaretPosition($input[0]) === 0) {
  389 + var next = $inputWrapper.next();
  390 + if (next.length) {
  391 + self.remove(next.data('item'));
  392 + }
  393 + }
  394 + break;
  395 +
  396 + // LEFT ARROW
  397 + case 37:
  398 + // Try to move the input before the previous tag
  399 + var $prevTag = $inputWrapper.prev();
  400 + if ($input.val().length === 0 && $prevTag[0]) {
  401 + $prevTag.before($inputWrapper);
  402 + $input.focus();
  403 + }
  404 + break;
  405 + // RIGHT ARROW
  406 + case 39:
  407 + // Try to move the input after the next tag
  408 + var $nextTag = $inputWrapper.next();
  409 + if ($input.val().length === 0 && $nextTag[0]) {
  410 + $nextTag.after($inputWrapper);
  411 + $input.focus();
  412 + }
  413 + break;
  414 + default:
  415 + // ignore
  416 + }
  417 +
  418 + // Reset internal input's size
  419 + var textLength = $input.val().length,
  420 + wordSpace = Math.ceil(textLength / 5),
  421 + size = textLength + wordSpace + 1;
  422 + $input.attr('size', Math.max(this.inputSize, $input.val().length));
  423 + }, self));
  424 +
  425 + self.$container.on('keypress', 'input', $.proxy(function(event) {
  426 + event.stopPropagation();
  427 + var $input = $(event.target);
  428 +
  429 + if (self.$element.attr('disabled')) {
  430 + self.$input.attr('disabled', 'disabled');
  431 + return;
  432 + }
  433 + var text = $input.val(),
  434 + maxLengthReached = self.options.maxChars && text.length >= self.options.maxChars;
  435 + if (self.options.freeInput && (keyCombinationInList(event, self.options.confirmKeys) || maxLengthReached)) {
  436 + // Only attempt to add a tag if there is data in the field
  437 + if (text.length !== 0) {
  438 + self.add(maxLengthReached ? text.substr(0, self.options.maxChars) : text);
  439 + $input.val('');
  440 + }
  441 +
  442 + // If the field is empty, let the event triggered fire as usual
  443 + if (self.options.cancelConfirmKeysOnEmpty === false) {
  444 + event.preventDefault();
  445 + }
  446 + }
  447 +
  448 + // Reset internal input's size
  449 + var textLength = $input.val().length,
  450 + wordSpace = Math.ceil(textLength / 5),
  451 + size = textLength + wordSpace + 1;
  452 + $input.attr('size', Math.max(this.inputSize, $input.val().length));
  453 + if(keyCombinationInList(event, [13]) ){
  454 + return false;
  455 + }else{
  456 + return true;
  457 + }
  458 +
  459 + }, self));
  460 +
  461 + // Remove icon clicked
  462 + self.$container.on('click', '[data-role=remove]', $.proxy(function(event) {
  463 + if (self.$element.attr('disabled')) {
  464 + return;
  465 + }
  466 + self.remove($(event.target).closest('.tag').data('item'));
  467 + }, self));
  468 +
  469 + // Only add existing value as tags when using strings as tags
  470 + if (self.options.itemValue === defaultOptions.itemValue) {
  471 + if (self.$element[0].tagName === 'INPUT') {
  472 + self.add(self.$element.val());
  473 + } else {
  474 + $('option', self.$element).each(function() {
  475 + self.add($(this).attr('value'), true);
  476 + });
  477 + }
  478 + }
  479 + },
  480 +
  481 + /**
  482 + * Removes all tagsinput behaviour and unregsiter all event handlers
  483 + */
  484 + destroy: function() {
  485 + var self = this;
  486 +
  487 + // Unbind events
  488 + self.$container.off('keypress', 'input');
  489 + self.$container.off('click', '[role=remove]');
  490 +
  491 + self.$container.remove();
  492 + self.$element.removeData('tagsinput');
  493 + self.$element.show();
  494 + },
  495 +
  496 + /**
  497 + * Sets focus on the tagsinput
  498 + */
  499 + focus: function() {
  500 + this.$input.focus();
  501 + },
  502 +
  503 + /**
  504 + * Returns the internal input element
  505 + */
  506 + input: function() {
  507 + return this.$input;
  508 + },
  509 +
  510 + /**
  511 + * Returns the element which is wrapped around the internal input. This
  512 + * is normally the $container, but typeahead.js moves the $input element.
  513 + */
  514 + findInputWrapper: function() {
  515 + var elt = this.$input[0],
  516 + container = this.$container[0];
  517 + while(elt && elt.parentNode !== container)
  518 + elt = elt.parentNode;
  519 +
  520 + return $(elt);
  521 + }
  522 + };
  523 +
  524 + /**
  525 + * Register JQuery plugin
  526 + */
  527 + $.fn.tagsinput = function(arg1, arg2, arg3) {
  528 + var results = [];
  529 +
  530 + this.each(function() {
  531 + var tagsinput = $(this).data('tagsinput');
  532 + // Initialize a new tags input
  533 + if (!tagsinput) {
  534 + tagsinput = new TagsInput(this, arg1);
  535 + $(this).data('tagsinput', tagsinput);
  536 + results.push(tagsinput);
  537 +
  538 + if (this.tagName === 'SELECT') {
  539 + $('option', $(this)).attr('selected', 'selected');
  540 + }
  541 +
  542 + // Init tags from $(this).val()
  543 + $(this).val($(this).val());
  544 + } else if (!arg1 && !arg2) {
  545 + // tagsinput already exists
  546 + // no function, trying to init
  547 + results.push(tagsinput);
  548 + } else if(tagsinput[arg1] !== undefined) {
  549 + // Invoke function on existing tags input
  550 + if(tagsinput[arg1].length === 3 && arg3 !== undefined){
  551 + var retVal = tagsinput[arg1](arg2, null, arg3);
  552 + }else{
  553 + var retVal = tagsinput[arg1](arg2);
  554 + }
  555 + if (retVal !== undefined)
  556 + results.push(retVal);
  557 + }
  558 + });
  559 +
  560 + if ( typeof arg1 == 'string') {
  561 + // Return the results from the invoked function calls
  562 + return results.length > 1 ? results : results[0];
  563 + } else {
  564 + return results;
  565 + }
  566 + };
  567 +
  568 + $.fn.tagsinput.Constructor = TagsInput;
  569 +
  570 + /**
  571 + * Most options support both a string or number as well as a function as
  572 + * option value. This function makes sure that the option with the given
  573 + * key in the given options is wrapped in a function
  574 + */
  575 + function makeOptionItemFunction(options, key) {
  576 + if (typeof options[key] !== 'function') {
  577 + var propertyName = options[key];
  578 + options[key] = function(item) { return item[propertyName]; };
  579 + }
  580 + }
  581 + function makeOptionFunction(options, key) {
  582 + if (typeof options[key] !== 'function') {
  583 + var value = options[key];
  584 + options[key] = function() { return value; };
  585 + }
  586 + }
  587 + /**
  588 + * HtmlEncodes the given value
  589 + */
  590 + var htmlEncodeContainer = $('<div />');
  591 + function htmlEncode(value) {
  592 + if (value) {
  593 + return htmlEncodeContainer.text(value).html();
  594 + } else {
  595 + return '';
  596 + }
  597 + }
  598 +
  599 + /**
  600 + * Returns the position of the caret in the given input field
  601 + * http://flightschool.acylt.com/devnotes/caret-position-woes/
  602 + */
  603 + function doGetCaretPosition(oField) {
  604 + var iCaretPos = 0;
  605 + if (document.selection) {
  606 + oField.focus ();
  607 + var oSel = document.selection.createRange();
  608 + oSel.moveStart ('character', -oField.value.length);
  609 + iCaretPos = oSel.text.length;
  610 + } else if (oField.selectionStart || oField.selectionStart == '0') {
  611 + iCaretPos = oField.selectionStart;
  612 + }
  613 + return (iCaretPos);
  614 + }
  615 +
  616 + /**
  617 + * Returns boolean indicates whether user has pressed an expected key combination.
  618 + * @param object keyPressEvent: JavaScript event object, refer
  619 + * http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
  620 + * @param object lookupList: expected key combinations, as in:
  621 + * [13, {which: 188, shiftKey: true}]
  622 + */
  623 + function keyCombinationInList(keyPressEvent, lookupList) {
  624 + var found = false;
  625 + $.each(lookupList, function (index, keyCombination) {
  626 + if (typeof (keyCombination) === 'number' && keyPressEvent.which === keyCombination) {
  627 + found = true;
  628 + return false;
  629 + }
  630 +
  631 + if (keyPressEvent.which === keyCombination.which) {
  632 + var alt = !keyCombination.hasOwnProperty('altKey') || keyPressEvent.altKey === keyCombination.altKey,
  633 + shift = !keyCombination.hasOwnProperty('shiftKey') || keyPressEvent.shiftKey === keyCombination.shiftKey,
  634 + ctrl = !keyCombination.hasOwnProperty('ctrlKey') || keyPressEvent.ctrlKey === keyCombination.ctrlKey;
  635 + if (alt && shift && ctrl) {
  636 + found = true;
  637 + return false;
  638 + }
  639 + }
  640 + });
  641 +
  642 + return found;
  643 + }
  644 +
  645 + /**
  646 + * Initialize tagsinput behaviour on inputs and selects which have
  647 + * data-role=tagsinput
  648 + */
  649 +
  650 + $(function() {
  651 + $("input[data-role=tagsinput], select[multiple][data-role=tagsinput]").tagsinput();
  652 + });
  653 +})(window.jQuery);
... ...
  1 +/*!
  2 + * typeahead.js 0.11.1
  3 + * https://github.com/twitter/typeahead.js
  4 + * Copyright 2013-2015 Twitter, Inc. and other contributors; Licensed MIT
  5 + */
  6 +
  7 +(function(root, factory) {
  8 + if (typeof define === "function" && define.amd) {
  9 + define("bloodhound", [ "jquery" ], function(a0) {
  10 + return root["Bloodhound"] = factory(a0);
  11 + });
  12 + } else if (typeof exports === "object") {
  13 + module.exports = factory(require("jquery"));
  14 + } else {
  15 + root["Bloodhound"] = factory(jQuery);
  16 + }
  17 +})(this, function($) {
  18 + var _ = function() {
  19 + "use strict";
  20 + return {
  21 + isMsie: function() {
  22 + return /(msie|trident)/i.test(navigator.userAgent) ? navigator.userAgent.match(/(msie |rv:)(\d+(.\d+)?)/i)[2] : false;
  23 + },
  24 + isBlankString: function(str) {
  25 + return !str || /^\s*$/.test(str);
  26 + },
  27 + escapeRegExChars: function(str) {
  28 + return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
  29 + },
  30 + isString: function(obj) {
  31 + return typeof obj === "string";
  32 + },
  33 + isNumber: function(obj) {
  34 + return typeof obj === "number";
  35 + },
  36 + isArray: $.isArray,
  37 + isFunction: $.isFunction,
  38 + isObject: $.isPlainObject,
  39 + isUndefined: function(obj) {
  40 + return typeof obj === "undefined";
  41 + },
  42 + isElement: function(obj) {
  43 + return !!(obj && obj.nodeType === 1);
  44 + },
  45 + isJQuery: function(obj) {
  46 + return obj instanceof $;
  47 + },
  48 + toStr: function toStr(s) {
  49 + return _.isUndefined(s) || s === null ? "" : s + "";
  50 + },
  51 + bind: $.proxy,
  52 + each: function(collection, cb) {
  53 + $.each(collection, reverseArgs);
  54 + function reverseArgs(index, value) {
  55 + return cb(value, index);
  56 + }
  57 + },
  58 + map: $.map,
  59 + filter: $.grep,
  60 + every: function(obj, test) {
  61 + var result = true;
  62 + if (!obj) {
  63 + return result;
  64 + }
  65 + $.each(obj, function(key, val) {
  66 + if (!(result = test.call(null, val, key, obj))) {
  67 + return false;
  68 + }
  69 + });
  70 + return !!result;
  71 + },
  72 + some: function(obj, test) {
  73 + var result = false;
  74 + if (!obj) {
  75 + return result;
  76 + }
  77 + $.each(obj, function(key, val) {
  78 + if (result = test.call(null, val, key, obj)) {
  79 + return false;
  80 + }
  81 + });
  82 + return !!result;
  83 + },
  84 + mixin: $.extend,
  85 + identity: function(x) {
  86 + return x;
  87 + },
  88 + clone: function(obj) {
  89 + return $.extend(true, {}, obj);
  90 + },
  91 + getIdGenerator: function() {
  92 + var counter = 0;
  93 + return function() {
  94 + return counter++;
  95 + };
  96 + },
  97 + templatify: function templatify(obj) {
  98 + return $.isFunction(obj) ? obj : template;
  99 + function template() {
  100 + return String(obj);
  101 + }
  102 + },
  103 + defer: function(fn) {
  104 + setTimeout(fn, 0);
  105 + },
  106 + debounce: function(func, wait, immediate) {
  107 + var timeout, result;
  108 + return function() {
  109 + var context = this, args = arguments, later, callNow;
  110 + later = function() {
  111 + timeout = null;
  112 + if (!immediate) {
  113 + result = func.apply(context, args);
  114 + }
  115 + };
  116 + callNow = immediate && !timeout;
  117 + clearTimeout(timeout);
  118 + timeout = setTimeout(later, wait);
  119 + if (callNow) {
  120 + result = func.apply(context, args);
  121 + }
  122 + return result;
  123 + };
  124 + },
  125 + throttle: function(func, wait) {
  126 + var context, args, timeout, result, previous, later;
  127 + previous = 0;
  128 + later = function() {
  129 + previous = new Date();
  130 + timeout = null;
  131 + result = func.apply(context, args);
  132 + };
  133 + return function() {
  134 + var now = new Date(), remaining = wait - (now - previous);
  135 + context = this;
  136 + args = arguments;
  137 + if (remaining <= 0) {
  138 + clearTimeout(timeout);
  139 + timeout = null;
  140 + previous = now;
  141 + result = func.apply(context, args);
  142 + } else if (!timeout) {
  143 + timeout = setTimeout(later, remaining);
  144 + }
  145 + return result;
  146 + };
  147 + },
  148 + stringify: function(val) {
  149 + return _.isString(val) ? val : JSON.stringify(val);
  150 + },
  151 + noop: function() {}
  152 + };
  153 + }();
  154 + var VERSION = "0.11.1";
  155 + var tokenizers = function() {
  156 + "use strict";
  157 + return {
  158 + nonword: nonword,
  159 + whitespace: whitespace,
  160 + obj: {
  161 + nonword: getObjTokenizer(nonword),
  162 + whitespace: getObjTokenizer(whitespace)
  163 + }
  164 + };
  165 + function whitespace(str) {
  166 + str = _.toStr(str);
  167 + return str ? str.split(/\s+/) : [];
  168 + }
  169 + function nonword(str) {
  170 + str = _.toStr(str);
  171 + return str ? str.split(/\W+/) : [];
  172 + }
  173 + function getObjTokenizer(tokenizer) {
  174 + return function setKey(keys) {
  175 + keys = _.isArray(keys) ? keys : [].slice.call(arguments, 0);
  176 + return function tokenize(o) {
  177 + var tokens = [];
  178 + _.each(keys, function(k) {
  179 + tokens = tokens.concat(tokenizer(_.toStr(o[k])));
  180 + });
  181 + return tokens;
  182 + };
  183 + };
  184 + }
  185 + }();
  186 + var LruCache = function() {
  187 + "use strict";
  188 + function LruCache(maxSize) {
  189 + this.maxSize = _.isNumber(maxSize) ? maxSize : 100;
  190 + this.reset();
  191 + if (this.maxSize <= 0) {
  192 + this.set = this.get = $.noop;
  193 + }
  194 + }
  195 + _.mixin(LruCache.prototype, {
  196 + set: function set(key, val) {
  197 + var tailItem = this.list.tail, node;
  198 + if (this.size >= this.maxSize) {
  199 + this.list.remove(tailItem);
  200 + delete this.hash[tailItem.key];
  201 + this.size--;
  202 + }
  203 + if (node = this.hash[key]) {
  204 + node.val = val;
  205 + this.list.moveToFront(node);
  206 + } else {
  207 + node = new Node(key, val);
  208 + this.list.add(node);
  209 + this.hash[key] = node;
  210 + this.size++;
  211 + }
  212 + },
  213 + get: function get(key) {
  214 + var node = this.hash[key];
  215 + if (node) {
  216 + this.list.moveToFront(node);
  217 + return node.val;
  218 + }
  219 + },
  220 + reset: function reset() {
  221 + this.size = 0;
  222 + this.hash = {};
  223 + this.list = new List();
  224 + }
  225 + });
  226 + function List() {
  227 + this.head = this.tail = null;
  228 + }
  229 + _.mixin(List.prototype, {
  230 + add: function add(node) {
  231 + if (this.head) {
  232 + node.next = this.head;
  233 + this.head.prev = node;
  234 + }
  235 + this.head = node;
  236 + this.tail = this.tail || node;
  237 + },
  238 + remove: function remove(node) {
  239 + node.prev ? node.prev.next = node.next : this.head = node.next;
  240 + node.next ? node.next.prev = node.prev : this.tail = node.prev;
  241 + },
  242 + moveToFront: function(node) {
  243 + this.remove(node);
  244 + this.add(node);
  245 + }
  246 + });
  247 + function Node(key, val) {
  248 + this.key = key;
  249 + this.val = val;
  250 + this.prev = this.next = null;
  251 + }
  252 + return LruCache;
  253 + }();
  254 + var PersistentStorage = function() {
  255 + "use strict";
  256 + var LOCAL_STORAGE;
  257 + try {
  258 + LOCAL_STORAGE = window.localStorage;
  259 + LOCAL_STORAGE.setItem("~~~", "!");
  260 + LOCAL_STORAGE.removeItem("~~~");
  261 + } catch (err) {
  262 + LOCAL_STORAGE = null;
  263 + }
  264 + function PersistentStorage(namespace, override) {
  265 + this.prefix = [ "__", namespace, "__" ].join("");
  266 + this.ttlKey = "__ttl__";
  267 + this.keyMatcher = new RegExp("^" + _.escapeRegExChars(this.prefix));
  268 + this.ls = override || LOCAL_STORAGE;
  269 + !this.ls && this._noop();
  270 + }
  271 + _.mixin(PersistentStorage.prototype, {
  272 + _prefix: function(key) {
  273 + return this.prefix + key;
  274 + },
  275 + _ttlKey: function(key) {
  276 + return this._prefix(key) + this.ttlKey;
  277 + },
  278 + _noop: function() {
  279 + this.get = this.set = this.remove = this.clear = this.isExpired = _.noop;
  280 + },
  281 + _safeSet: function(key, val) {
  282 + try {
  283 + this.ls.setItem(key, val);
  284 + } catch (err) {
  285 + if (err.name === "QuotaExceededError") {
  286 + this.clear();
  287 + this._noop();
  288 + }
  289 + }
  290 + },
  291 + get: function(key) {
  292 + if (this.isExpired(key)) {
  293 + this.remove(key);
  294 + }
  295 + return decode(this.ls.getItem(this._prefix(key)));
  296 + },
  297 + set: function(key, val, ttl) {
  298 + if (_.isNumber(ttl)) {
  299 + this._safeSet(this._ttlKey(key), encode(now() + ttl));
  300 + } else {
  301 + this.ls.removeItem(this._ttlKey(key));
  302 + }
  303 + return this._safeSet(this._prefix(key), encode(val));
  304 + },
  305 + remove: function(key) {
  306 + this.ls.removeItem(this._ttlKey(key));
  307 + this.ls.removeItem(this._prefix(key));
  308 + return this;
  309 + },
  310 + clear: function() {
  311 + var i, keys = gatherMatchingKeys(this.keyMatcher);
  312 + for (i = keys.length; i--; ) {
  313 + this.remove(keys[i]);
  314 + }
  315 + return this;
  316 + },
  317 + isExpired: function(key) {
  318 + var ttl = decode(this.ls.getItem(this._ttlKey(key)));
  319 + return _.isNumber(ttl) && now() > ttl ? true : false;
  320 + }
  321 + });
  322 + return PersistentStorage;
  323 + function now() {
  324 + return new Date().getTime();
  325 + }
  326 + function encode(val) {
  327 + return JSON.stringify(_.isUndefined(val) ? null : val);
  328 + }
  329 + function decode(val) {
  330 + return $.parseJSON(val);
  331 + }
  332 + function gatherMatchingKeys(keyMatcher) {
  333 + var i, key, keys = [], len = LOCAL_STORAGE.length;
  334 + for (i = 0; i < len; i++) {
  335 + if ((key = LOCAL_STORAGE.key(i)).match(keyMatcher)) {
  336 + keys.push(key.replace(keyMatcher, ""));
  337 + }
  338 + }
  339 + return keys;
  340 + }
  341 + }();
  342 + var Transport = function() {
  343 + "use strict";
  344 + var pendingRequestsCount = 0, pendingRequests = {}, maxPendingRequests = 6, sharedCache = new LruCache(10);
  345 + function Transport(o) {
  346 + o = o || {};
  347 + this.cancelled = false;
  348 + this.lastReq = null;
  349 + this._send = o.transport;
  350 + this._get = o.limiter ? o.limiter(this._get) : this._get;
  351 + this._cache = o.cache === false ? new LruCache(0) : sharedCache;
  352 + }
  353 + Transport.setMaxPendingRequests = function setMaxPendingRequests(num) {
  354 + maxPendingRequests = num;
  355 + };
  356 + Transport.resetCache = function resetCache() {
  357 + sharedCache.reset();
  358 + };
  359 + _.mixin(Transport.prototype, {
  360 + _fingerprint: function fingerprint(o) {
  361 + o = o || {};
  362 + return o.url + o.type + $.param(o.data || {});
  363 + },
  364 + _get: function(o, cb) {
  365 + var that = this, fingerprint, jqXhr;
  366 + fingerprint = this._fingerprint(o);
  367 + if (this.cancelled || fingerprint !== this.lastReq) {
  368 + return;
  369 + }
  370 + if (jqXhr = pendingRequests[fingerprint]) {
  371 + jqXhr.done(done).fail(fail);
  372 + } else if (pendingRequestsCount < maxPendingRequests) {
  373 + pendingRequestsCount++;
  374 + pendingRequests[fingerprint] = this._send(o).done(done).fail(fail).always(always);
  375 + } else {
  376 + this.onDeckRequestArgs = [].slice.call(arguments, 0);
  377 + }
  378 + function done(resp) {
  379 + cb(null, resp);
  380 + that._cache.set(fingerprint, resp);
  381 + }
  382 + function fail() {
  383 + cb(true);
  384 + }
  385 + function always() {
  386 + pendingRequestsCount--;
  387 + delete pendingRequests[fingerprint];
  388 + if (that.onDeckRequestArgs) {
  389 + that._get.apply(that, that.onDeckRequestArgs);
  390 + that.onDeckRequestArgs = null;
  391 + }
  392 + }
  393 + },
  394 + get: function(o, cb) {
  395 + var resp, fingerprint;
  396 + cb = cb || $.noop;
  397 + o = _.isString(o) ? {
  398 + url: o
  399 + } : o || {};
  400 + fingerprint = this._fingerprint(o);
  401 + this.cancelled = false;
  402 + this.lastReq = fingerprint;
  403 + if (resp = this._cache.get(fingerprint)) {
  404 + cb(null, resp);
  405 + } else {
  406 + this._get(o, cb);
  407 + }
  408 + },
  409 + cancel: function() {
  410 + this.cancelled = true;
  411 + }
  412 + });
  413 + return Transport;
  414 + }();
  415 + var SearchIndex = window.SearchIndex = function() {
  416 + "use strict";
  417 + var CHILDREN = "c", IDS = "i";
  418 + function SearchIndex(o) {
  419 + o = o || {};
  420 + if (!o.datumTokenizer || !o.queryTokenizer) {
  421 + $.error("datumTokenizer and queryTokenizer are both required");
  422 + }
  423 + this.identify = o.identify || _.stringify;
  424 + this.datumTokenizer = o.datumTokenizer;
  425 + this.queryTokenizer = o.queryTokenizer;
  426 + this.reset();
  427 + }
  428 + _.mixin(SearchIndex.prototype, {
  429 + bootstrap: function bootstrap(o) {
  430 + this.datums = o.datums;
  431 + this.trie = o.trie;
  432 + },
  433 + add: function(data) {
  434 + var that = this;
  435 + data = _.isArray(data) ? data : [ data ];
  436 + _.each(data, function(datum) {
  437 + var id, tokens;
  438 + that.datums[id = that.identify(datum)] = datum;
  439 + tokens = normalizeTokens(that.datumTokenizer(datum));
  440 + _.each(tokens, function(token) {
  441 + var node, chars, ch;
  442 + node = that.trie;
  443 + chars = token.split("");
  444 + while (ch = chars.shift()) {
  445 + node = node[CHILDREN][ch] || (node[CHILDREN][ch] = newNode());
  446 + node[IDS].push(id);
  447 + }
  448 + });
  449 + });
  450 + },
  451 + get: function get(ids) {
  452 + var that = this;
  453 + return _.map(ids, function(id) {
  454 + return that.datums[id];
  455 + });
  456 + },
  457 + search: function search(query) {
  458 + var that = this, tokens, matches;
  459 + tokens = normalizeTokens(this.queryTokenizer(query));
  460 + _.each(tokens, function(token) {
  461 + var node, chars, ch, ids;
  462 + if (matches && matches.length === 0) {
  463 + return false;
  464 + }
  465 + node = that.trie;
  466 + chars = token.split("");
  467 + while (node && (ch = chars.shift())) {
  468 + node = node[CHILDREN][ch];
  469 + }
  470 + if (node && chars.length === 0) {
  471 + ids = node[IDS].slice(0);
  472 + matches = matches ? getIntersection(matches, ids) : ids;
  473 + } else {
  474 + matches = [];
  475 + return false;
  476 + }
  477 + });
  478 + return matches ? _.map(unique(matches), function(id) {
  479 + return that.datums[id];
  480 + }) : [];
  481 + },
  482 + all: function all() {
  483 + var values = [];
  484 + for (var key in this.datums) {
  485 + values.push(this.datums[key]);
  486 + }
  487 + return values;
  488 + },
  489 + reset: function reset() {
  490 + this.datums = {};
  491 + this.trie = newNode();
  492 + },
  493 + serialize: function serialize() {
  494 + return {
  495 + datums: this.datums,
  496 + trie: this.trie
  497 + };
  498 + }
  499 + });
  500 + return SearchIndex;
  501 + function normalizeTokens(tokens) {
  502 + tokens = _.filter(tokens, function(token) {
  503 + return !!token;
  504 + });
  505 + tokens = _.map(tokens, function(token) {
  506 + return token.toLowerCase();
  507 + });
  508 + return tokens;
  509 + }
  510 + function newNode() {
  511 + var node = {};
  512 + node[IDS] = [];
  513 + node[CHILDREN] = {};
  514 + return node;
  515 + }
  516 + function unique(array) {
  517 + var seen = {}, uniques = [];
  518 + for (var i = 0, len = array.length; i < len; i++) {
  519 + if (!seen[array[i]]) {
  520 + seen[array[i]] = true;
  521 + uniques.push(array[i]);
  522 + }
  523 + }
  524 + return uniques;
  525 + }
  526 + function getIntersection(arrayA, arrayB) {
  527 + var ai = 0, bi = 0, intersection = [];
  528 + arrayA = arrayA.sort();
  529 + arrayB = arrayB.sort();
  530 + var lenArrayA = arrayA.length, lenArrayB = arrayB.length;
  531 + while (ai < lenArrayA && bi < lenArrayB) {
  532 + if (arrayA[ai] < arrayB[bi]) {
  533 + ai++;
  534 + } else if (arrayA[ai] > arrayB[bi]) {
  535 + bi++;
  536 + } else {
  537 + intersection.push(arrayA[ai]);
  538 + ai++;
  539 + bi++;
  540 + }
  541 + }
  542 + return intersection;
  543 + }
  544 + }();
  545 + var Prefetch = function() {
  546 + "use strict";
  547 + var keys;
  548 + keys = {
  549 + data: "data",
  550 + protocol: "protocol",
  551 + thumbprint: "thumbprint"
  552 + };
  553 + function Prefetch(o) {
  554 + this.url = o.url;
  555 + this.ttl = o.ttl;
  556 + this.cache = o.cache;
  557 + this.prepare = o.prepare;
  558 + this.transform = o.transform;
  559 + this.transport = o.transport;
  560 + this.thumbprint = o.thumbprint;
  561 + this.storage = new PersistentStorage(o.cacheKey);
  562 + }
  563 + _.mixin(Prefetch.prototype, {
  564 + _settings: function settings() {
  565 + return {
  566 + url: this.url,
  567 + type: "GET",
  568 + dataType: "json"
  569 + };
  570 + },
  571 + store: function store(data) {
  572 + if (!this.cache) {
  573 + return;
  574 + }
  575 + this.storage.set(keys.data, data, this.ttl);
  576 + this.storage.set(keys.protocol, location.protocol, this.ttl);
  577 + this.storage.set(keys.thumbprint, this.thumbprint, this.ttl);
  578 + },
  579 + fromCache: function fromCache() {
  580 + var stored = {}, isExpired;
  581 + if (!this.cache) {
  582 + return null;
  583 + }
  584 + stored.data = this.storage.get(keys.data);
  585 + stored.protocol = this.storage.get(keys.protocol);
  586 + stored.thumbprint = this.storage.get(keys.thumbprint);
  587 + isExpired = stored.thumbprint !== this.thumbprint || stored.protocol !== location.protocol;
  588 + return stored.data && !isExpired ? stored.data : null;
  589 + },
  590 + fromNetwork: function(cb) {
  591 + var that = this, settings;
  592 + if (!cb) {
  593 + return;
  594 + }
  595 + settings = this.prepare(this._settings());
  596 + this.transport(settings).fail(onError).done(onResponse);
  597 + function onError() {
  598 + cb(true);
  599 + }
  600 + function onResponse(resp) {
  601 + cb(null, that.transform(resp));
  602 + }
  603 + },
  604 + clear: function clear() {
  605 + this.storage.clear();
  606 + return this;
  607 + }
  608 + });
  609 + return Prefetch;
  610 + }();
  611 + var Remote = function() {
  612 + "use strict";
  613 + function Remote(o) {
  614 + this.url = o.url;
  615 + this.prepare = o.prepare;
  616 + this.transform = o.transform;
  617 + this.transport = new Transport({
  618 + cache: o.cache,
  619 + limiter: o.limiter,
  620 + transport: o.transport
  621 + });
  622 + }
  623 + _.mixin(Remote.prototype, {
  624 + _settings: function settings() {
  625 + return {
  626 + url: this.url,
  627 + type: "GET",
  628 + dataType: "json"
  629 + };
  630 + },
  631 + get: function get(query, cb) {
  632 + var that = this, settings;
  633 + if (!cb) {
  634 + return;
  635 + }
  636 + query = query || "";
  637 + settings = this.prepare(query, this._settings());
  638 + return this.transport.get(settings, onResponse);
  639 + function onResponse(err, resp) {
  640 + err ? cb([]) : cb(that.transform(resp));
  641 + }
  642 + },
  643 + cancelLastRequest: function cancelLastRequest() {
  644 + this.transport.cancel();
  645 + }
  646 + });
  647 + return Remote;
  648 + }();
  649 + var oParser = function() {
  650 + "use strict";
  651 + return function parse(o) {
  652 + var defaults, sorter;
  653 + defaults = {
  654 + initialize: true,
  655 + identify: _.stringify,
  656 + datumTokenizer: null,
  657 + queryTokenizer: null,
  658 + sufficient: 5,
  659 + sorter: null,
  660 + local: [],
  661 + prefetch: null,
  662 + remote: null
  663 + };
  664 + o = _.mixin(defaults, o || {});
  665 + !o.datumTokenizer && $.error("datumTokenizer is required");
  666 + !o.queryTokenizer && $.error("queryTokenizer is required");
  667 + sorter = o.sorter;
  668 + o.sorter = sorter ? function(x) {
  669 + return x.sort(sorter);
  670 + } : _.identity;
  671 + o.local = _.isFunction(o.local) ? o.local() : o.local;
  672 + o.prefetch = parsePrefetch(o.prefetch);
  673 + o.remote = parseRemote(o.remote);
  674 + return o;
  675 + };
  676 + function parsePrefetch(o) {
  677 + var defaults;
  678 + if (!o) {
  679 + return null;
  680 + }
  681 + defaults = {
  682 + url: null,
  683 + ttl: 24 * 60 * 60 * 1e3,
  684 + cache: true,
  685 + cacheKey: null,
  686 + thumbprint: "",
  687 + prepare: _.identity,
  688 + transform: _.identity,
  689 + transport: null
  690 + };
  691 + o = _.isString(o) ? {
  692 + url: o
  693 + } : o;
  694 + o = _.mixin(defaults, o);
  695 + !o.url && $.error("prefetch requires url to be set");
  696 + o.transform = o.filter || o.transform;
  697 + o.cacheKey = o.cacheKey || o.url;
  698 + o.thumbprint = VERSION + o.thumbprint;
  699 + o.transport = o.transport ? callbackToDeferred(o.transport) : $.ajax;
  700 + return o;
  701 + }
  702 + function parseRemote(o) {
  703 + var defaults;
  704 + if (!o) {
  705 + return;
  706 + }
  707 + defaults = {
  708 + url: null,
  709 + cache: true,
  710 + prepare: null,
  711 + replace: null,
  712 + wildcard: null,
  713 + limiter: null,
  714 + rateLimitBy: "debounce",
  715 + rateLimitWait: 300,
  716 + transform: _.identity,
  717 + transport: null
  718 + };
  719 + o = _.isString(o) ? {
  720 + url: o
  721 + } : o;
  722 + o = _.mixin(defaults, o);
  723 + !o.url && $.error("remote requires url to be set");
  724 + o.transform = o.filter || o.transform;
  725 + o.prepare = toRemotePrepare(o);
  726 + o.limiter = toLimiter(o);
  727 + o.transport = o.transport ? callbackToDeferred(o.transport) : $.ajax;
  728 + delete o.replace;
  729 + delete o.wildcard;
  730 + delete o.rateLimitBy;
  731 + delete o.rateLimitWait;
  732 + return o;
  733 + }
  734 + function toRemotePrepare(o) {
  735 + var prepare, replace, wildcard;
  736 + prepare = o.prepare;
  737 + replace = o.replace;
  738 + wildcard = o.wildcard;
  739 + if (prepare) {
  740 + return prepare;
  741 + }
  742 + if (replace) {
  743 + prepare = prepareByReplace;
  744 + } else if (o.wildcard) {
  745 + prepare = prepareByWildcard;
  746 + } else {
  747 + prepare = idenityPrepare;
  748 + }
  749 + return prepare;
  750 + function prepareByReplace(query, settings) {
  751 + settings.url = replace(settings.url, query);
  752 + return settings;
  753 + }
  754 + function prepareByWildcard(query, settings) {
  755 + settings.url = settings.url.replace(wildcard, encodeURIComponent(query));
  756 + return settings;
  757 + }
  758 + function idenityPrepare(query, settings) {
  759 + return settings;
  760 + }
  761 + }
  762 + function toLimiter(o) {
  763 + var limiter, method, wait;
  764 + limiter = o.limiter;
  765 + method = o.rateLimitBy;
  766 + wait = o.rateLimitWait;
  767 + if (!limiter) {
  768 + limiter = /^throttle$/i.test(method) ? throttle(wait) : debounce(wait);
  769 + }
  770 + return limiter;
  771 + function debounce(wait) {
  772 + return function debounce(fn) {
  773 + return _.debounce(fn, wait);
  774 + };
  775 + }
  776 + function throttle(wait) {
  777 + return function throttle(fn) {
  778 + return _.throttle(fn, wait);
  779 + };
  780 + }
  781 + }
  782 + function callbackToDeferred(fn) {
  783 + return function wrapper(o) {
  784 + var deferred = $.Deferred();
  785 + fn(o, onSuccess, onError);
  786 + return deferred;
  787 + function onSuccess(resp) {
  788 + _.defer(function() {
  789 + deferred.resolve(resp);
  790 + });
  791 + }
  792 + function onError(err) {
  793 + _.defer(function() {
  794 + deferred.reject(err);
  795 + });
  796 + }
  797 + };
  798 + }
  799 + }();
  800 + var Bloodhound = function() {
  801 + "use strict";
  802 + var old;
  803 + old = window && window.Bloodhound;
  804 + function Bloodhound(o) {
  805 + o = oParser(o);
  806 + this.sorter = o.sorter;
  807 + this.identify = o.identify;
  808 + this.sufficient = o.sufficient;
  809 + this.local = o.local;
  810 + this.remote = o.remote ? new Remote(o.remote) : null;
  811 + this.prefetch = o.prefetch ? new Prefetch(o.prefetch) : null;
  812 + this.index = new SearchIndex({
  813 + identify: this.identify,
  814 + datumTokenizer: o.datumTokenizer,
  815 + queryTokenizer: o.queryTokenizer
  816 + });
  817 + o.initialize !== false && this.initialize();
  818 + }
  819 + Bloodhound.noConflict = function noConflict() {
  820 + window && (window.Bloodhound = old);
  821 + return Bloodhound;
  822 + };
  823 + Bloodhound.tokenizers = tokenizers;
  824 + _.mixin(Bloodhound.prototype, {
  825 + __ttAdapter: function ttAdapter() {
  826 + var that = this;
  827 + return this.remote ? withAsync : withoutAsync;
  828 + function withAsync(query, sync, async) {
  829 + return that.search(query, sync, async);
  830 + }
  831 + function withoutAsync(query, sync) {
  832 + return that.search(query, sync);
  833 + }
  834 + },
  835 + _loadPrefetch: function loadPrefetch() {
  836 + var that = this, deferred, serialized;
  837 + deferred = $.Deferred();
  838 + if (!this.prefetch) {
  839 + deferred.resolve();
  840 + } else if (serialized = this.prefetch.fromCache()) {
  841 + this.index.bootstrap(serialized);
  842 + deferred.resolve();
  843 + } else {
  844 + this.prefetch.fromNetwork(done);
  845 + }
  846 + return deferred.promise();
  847 + function done(err, data) {
  848 + if (err) {
  849 + return deferred.reject();
  850 + }
  851 + that.add(data);
  852 + that.prefetch.store(that.index.serialize());
  853 + deferred.resolve();
  854 + }
  855 + },
  856 + _initialize: function initialize() {
  857 + var that = this, deferred;
  858 + this.clear();
  859 + (this.initPromise = this._loadPrefetch()).done(addLocalToIndex);
  860 + return this.initPromise;
  861 + function addLocalToIndex() {
  862 + that.add(that.local);
  863 + }
  864 + },
  865 + initialize: function initialize(force) {
  866 + return !this.initPromise || force ? this._initialize() : this.initPromise;
  867 + },
  868 + add: function add(data) {
  869 + this.index.add(data);
  870 + return this;
  871 + },
  872 + get: function get(ids) {
  873 + ids = _.isArray(ids) ? ids : [].slice.call(arguments);
  874 + return this.index.get(ids);
  875 + },
  876 + search: function search(query, sync, async) {
  877 + var that = this, local;
  878 + local = this.sorter(this.index.search(query));
  879 + sync(this.remote ? local.slice() : local);
  880 + if (this.remote && local.length < this.sufficient) {
  881 + this.remote.get(query, processRemote);
  882 + } else if (this.remote) {
  883 + this.remote.cancelLastRequest();
  884 + }
  885 + return this;
  886 + function processRemote(remote) {
  887 + var nonDuplicates = [];
  888 + _.each(remote, function(r) {
  889 + !_.some(local, function(l) {
  890 + return that.identify(r) === that.identify(l);
  891 + }) && nonDuplicates.push(r);
  892 + });
  893 + async && async(nonDuplicates);
  894 + }
  895 + },
  896 + all: function all() {
  897 + return this.index.all();
  898 + },
  899 + clear: function clear() {
  900 + this.index.reset();
  901 + return this;
  902 + },
  903 + clearPrefetchCache: function clearPrefetchCache() {
  904 + this.prefetch && this.prefetch.clear();
  905 + return this;
  906 + },
  907 + clearRemoteCache: function clearRemoteCache() {
  908 + Transport.resetCache();
  909 + return this;
  910 + },
  911 + ttAdapter: function ttAdapter() {
  912 + return this.__ttAdapter();
  913 + }
  914 + });
  915 + return Bloodhound;
  916 + }();
  917 + return Bloodhound;
  918 +});
  919 +
  920 +(function(root, factory) {
  921 + if (typeof define === "function" && define.amd) {
  922 + define("typeahead.js", [ "jquery" ], function(a0) {
  923 + return factory(a0);
  924 + });
  925 + } else if (typeof exports === "object") {
  926 + module.exports = factory(require("jquery"));
  927 + } else {
  928 + factory(jQuery);
  929 + }
  930 +})(this, function($) {
  931 + var _ = function() {
  932 + "use strict";
  933 + return {
  934 + isMsie: function() {
  935 + return /(msie|trident)/i.test(navigator.userAgent) ? navigator.userAgent.match(/(msie |rv:)(\d+(.\d+)?)/i)[2] : false;
  936 + },
  937 + isBlankString: function(str) {
  938 + return !str || /^\s*$/.test(str);
  939 + },
  940 + escapeRegExChars: function(str) {
  941 + return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
  942 + },
  943 + isString: function(obj) {
  944 + return typeof obj === "string";
  945 + },
  946 + isNumber: function(obj) {
  947 + return typeof obj === "number";
  948 + },
  949 + isArray: $.isArray,
  950 + isFunction: $.isFunction,
  951 + isObject: $.isPlainObject,
  952 + isUndefined: function(obj) {
  953 + return typeof obj === "undefined";
  954 + },
  955 + isElement: function(obj) {
  956 + return !!(obj && obj.nodeType === 1);
  957 + },
  958 + isJQuery: function(obj) {
  959 + return obj instanceof $;
  960 + },
  961 + toStr: function toStr(s) {
  962 + return _.isUndefined(s) || s === null ? "" : s + "";
  963 + },
  964 + bind: $.proxy,
  965 + each: function(collection, cb) {
  966 + $.each(collection, reverseArgs);
  967 + function reverseArgs(index, value) {
  968 + return cb(value, index);
  969 + }
  970 + },
  971 + map: $.map,
  972 + filter: $.grep,
  973 + every: function(obj, test) {
  974 + var result = true;
  975 + if (!obj) {
  976 + return result;
  977 + }
  978 + $.each(obj, function(key, val) {
  979 + if (!(result = test.call(null, val, key, obj))) {
  980 + return false;
  981 + }
  982 + });
  983 + return !!result;
  984 + },
  985 + some: function(obj, test) {
  986 + var result = false;
  987 + if (!obj) {
  988 + return result;
  989 + }
  990 + $.each(obj, function(key, val) {
  991 + if (result = test.call(null, val, key, obj)) {
  992 + return false;
  993 + }
  994 + });
  995 + return !!result;
  996 + },
  997 + mixin: $.extend,
  998 + identity: function(x) {
  999 + return x;
  1000 + },
  1001 + clone: function(obj) {
  1002 + return $.extend(true, {}, obj);
  1003 + },
  1004 + getIdGenerator: function() {
  1005 + var counter = 0;
  1006 + return function() {
  1007 + return counter++;
  1008 + };
  1009 + },
  1010 + templatify: function templatify(obj) {
  1011 + return $.isFunction(obj) ? obj : template;
  1012 + function template() {
  1013 + return String(obj);
  1014 + }
  1015 + },
  1016 + defer: function(fn) {
  1017 + setTimeout(fn, 0);
  1018 + },
  1019 + debounce: function(func, wait, immediate) {
  1020 + var timeout, result;
  1021 + return function() {
  1022 + var context = this, args = arguments, later, callNow;
  1023 + later = function() {
  1024 + timeout = null;
  1025 + if (!immediate) {
  1026 + result = func.apply(context, args);
  1027 + }
  1028 + };
  1029 + callNow = immediate && !timeout;
  1030 + clearTimeout(timeout);
  1031 + timeout = setTimeout(later, wait);
  1032 + if (callNow) {
  1033 + result = func.apply(context, args);
  1034 + }
  1035 + return result;
  1036 + };
  1037 + },
  1038 + throttle: function(func, wait) {
  1039 + var context, args, timeout, result, previous, later;
  1040 + previous = 0;
  1041 + later = function() {
  1042 + previous = new Date();
  1043 + timeout = null;
  1044 + result = func.apply(context, args);
  1045 + };
  1046 + return function() {
  1047 + var now = new Date(), remaining = wait - (now - previous);
  1048 + context = this;
  1049 + args = arguments;
  1050 + if (remaining <= 0) {
  1051 + clearTimeout(timeout);
  1052 + timeout = null;
  1053 + previous = now;
  1054 + result = func.apply(context, args);
  1055 + } else if (!timeout) {
  1056 + timeout = setTimeout(later, remaining);
  1057 + }
  1058 + return result;
  1059 + };
  1060 + },
  1061 + stringify: function(val) {
  1062 + return _.isString(val) ? val : JSON.stringify(val);
  1063 + },
  1064 + noop: function() {}
  1065 + };
  1066 + }();
  1067 + var WWW = function() {
  1068 + "use strict";
  1069 + var defaultClassNames = {
  1070 + wrapper: "twitter-typeahead",
  1071 + input: "tt-input",
  1072 + hint: "tt-hint",
  1073 + menu: "tt-menu",
  1074 + dataset: "tt-dataset",
  1075 + suggestion: "tt-suggestion",
  1076 + selectable: "tt-selectable",
  1077 + empty: "tt-empty",
  1078 + open: "tt-open",
  1079 + cursor: "tt-cursor",
  1080 + highlight: "tt-highlight"
  1081 + };
  1082 + return build;
  1083 + function build(o) {
  1084 + var www, classes;
  1085 + classes = _.mixin({}, defaultClassNames, o);
  1086 + www = {
  1087 + css: buildCss(),
  1088 + classes: classes,
  1089 + html: buildHtml(classes),
  1090 + selectors: buildSelectors(classes)
  1091 + };
  1092 + return {
  1093 + css: www.css,
  1094 + html: www.html,
  1095 + classes: www.classes,
  1096 + selectors: www.selectors,
  1097 + mixin: function(o) {
  1098 + _.mixin(o, www);
  1099 + }
  1100 + };
  1101 + }
  1102 + function buildHtml(c) {
  1103 + return {
  1104 + wrapper: '<span class="' + c.wrapper + '"></span>',
  1105 + menu: '<div class="' + c.menu + '"></div>'
  1106 + };
  1107 + }
  1108 + function buildSelectors(classes) {
  1109 + var selectors = {};
  1110 + _.each(classes, function(v, k) {
  1111 + selectors[k] = "." + v;
  1112 + });
  1113 + return selectors;
  1114 + }
  1115 + function buildCss() {
  1116 + var css = {
  1117 + wrapper: {
  1118 + position: "relative",
  1119 + display: "inline-block"
  1120 + },
  1121 + hint: {
  1122 + position: "absolute",
  1123 + top: "0",
  1124 + left: "0",
  1125 + borderColor: "transparent",
  1126 + boxShadow: "none",
  1127 + opacity: "1"
  1128 + },
  1129 + input: {
  1130 + position: "relative",
  1131 + verticalAlign: "top",
  1132 + backgroundColor: "transparent"
  1133 + },
  1134 + inputWithNoHint: {
  1135 + position: "relative",
  1136 + verticalAlign: "top"
  1137 + },
  1138 + menu: {
  1139 + position: "absolute",
  1140 + top: "100%",
  1141 + left: "0",
  1142 + zIndex: "100",
  1143 + display: "none"
  1144 + },
  1145 + ltr: {
  1146 + left: "0",
  1147 + right: "auto"
  1148 + },
  1149 + rtl: {
  1150 + left: "auto",
  1151 + right: " 0"
  1152 + }
  1153 + };
  1154 + if (_.isMsie()) {
  1155 + _.mixin(css.input, {
  1156 + backgroundImage: "url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)"
  1157 + });
  1158 + }
  1159 + return css;
  1160 + }
  1161 + }();
  1162 + var EventBus = function() {
  1163 + "use strict";
  1164 + var namespace, deprecationMap;
  1165 + namespace = "typeahead:";
  1166 + deprecationMap = {
  1167 + render: "rendered",
  1168 + cursorchange: "cursorchanged",
  1169 + select: "selected",
  1170 + autocomplete: "autocompleted"
  1171 + };
  1172 + function EventBus(o) {
  1173 + if (!o || !o.el) {
  1174 + $.error("EventBus initialized without el");
  1175 + }
  1176 + this.$el = $(o.el);
  1177 + }
  1178 + _.mixin(EventBus.prototype, {
  1179 + _trigger: function(type, args) {
  1180 + var $e;
  1181 + $e = $.Event(namespace + type);
  1182 + (args = args || []).unshift($e);
  1183 + this.$el.trigger.apply(this.$el, args);
  1184 + return $e;
  1185 + },
  1186 + before: function(type) {
  1187 + var args, $e;
  1188 + args = [].slice.call(arguments, 1);
  1189 + $e = this._trigger("before" + type, args);
  1190 + return $e.isDefaultPrevented();
  1191 + },
  1192 + trigger: function(type) {
  1193 + var deprecatedType;
  1194 + this._trigger(type, [].slice.call(arguments, 1));
  1195 + if (deprecatedType = deprecationMap[type]) {
  1196 + this._trigger(deprecatedType, [].slice.call(arguments, 1));
  1197 + }
  1198 + }
  1199 + });
  1200 + return EventBus;
  1201 + }();
  1202 + var EventEmitter = function() {
  1203 + "use strict";
  1204 + var splitter = /\s+/, nextTick = getNextTick();
  1205 + return {
  1206 + onSync: onSync,
  1207 + onAsync: onAsync,
  1208 + off: off,
  1209 + trigger: trigger
  1210 + };
  1211 + function on(method, types, cb, context) {
  1212 + var type;
  1213 + if (!cb) {
  1214 + return this;
  1215 + }
  1216 + types = types.split(splitter);
  1217 + cb = context ? bindContext(cb, context) : cb;
  1218 + this._callbacks = this._callbacks || {};
  1219 + while (type = types.shift()) {
  1220 + this._callbacks[type] = this._callbacks[type] || {
  1221 + sync: [],
  1222 + async: []
  1223 + };
  1224 + this._callbacks[type][method].push(cb);
  1225 + }
  1226 + return this;
  1227 + }
  1228 + function onAsync(types, cb, context) {
  1229 + return on.call(this, "async", types, cb, context);
  1230 + }
  1231 + function onSync(types, cb, context) {
  1232 + return on.call(this, "sync", types, cb, context);
  1233 + }
  1234 + function off(types) {
  1235 + var type;
  1236 + if (!this._callbacks) {
  1237 + return this;
  1238 + }
  1239 + types = types.split(splitter);
  1240 + while (type = types.shift()) {
  1241 + delete this._callbacks[type];
  1242 + }
  1243 + return this;
  1244 + }
  1245 + function trigger(types) {
  1246 + var type, callbacks, args, syncFlush, asyncFlush;
  1247 + if (!this._callbacks) {
  1248 + return this;
  1249 + }
  1250 + types = types.split(splitter);
  1251 + args = [].slice.call(arguments, 1);
  1252 + while ((type = types.shift()) && (callbacks = this._callbacks[type])) {
  1253 + syncFlush = getFlush(callbacks.sync, this, [ type ].concat(args));
  1254 + asyncFlush = getFlush(callbacks.async, this, [ type ].concat(args));
  1255 + syncFlush() && nextTick(asyncFlush);
  1256 + }
  1257 + return this;
  1258 + }
  1259 + function getFlush(callbacks, context, args) {
  1260 + return flush;
  1261 + function flush() {
  1262 + var cancelled;
  1263 + for (var i = 0, len = callbacks.length; !cancelled && i < len; i += 1) {
  1264 + cancelled = callbacks[i].apply(context, args) === false;
  1265 + }
  1266 + return !cancelled;
  1267 + }
  1268 + }
  1269 + function getNextTick() {
  1270 + var nextTickFn;
  1271 + if (window.setImmediate) {
  1272 + nextTickFn = function nextTickSetImmediate(fn) {
  1273 + setImmediate(function() {
  1274 + fn();
  1275 + });
  1276 + };
  1277 + } else {
  1278 + nextTickFn = function nextTickSetTimeout(fn) {
  1279 + setTimeout(function() {
  1280 + fn();
  1281 + }, 0);
  1282 + };
  1283 + }
  1284 + return nextTickFn;
  1285 + }
  1286 + function bindContext(fn, context) {
  1287 + return fn.bind ? fn.bind(context) : function() {
  1288 + fn.apply(context, [].slice.call(arguments, 0));
  1289 + };
  1290 + }
  1291 + }();
  1292 + var highlight = function(doc) {
  1293 + "use strict";
  1294 + var defaults = {
  1295 + node: null,
  1296 + pattern: null,
  1297 + tagName: "strong",
  1298 + className: null,
  1299 + wordsOnly: false,
  1300 + caseSensitive: false
  1301 + };
  1302 + return function hightlight(o) {
  1303 + var regex;
  1304 + o = _.mixin({}, defaults, o);
  1305 + if (!o.node || !o.pattern) {
  1306 + return;
  1307 + }
  1308 + o.pattern = _.isArray(o.pattern) ? o.pattern : [ o.pattern ];
  1309 + regex = getRegex(o.pattern, o.caseSensitive, o.wordsOnly);
  1310 + traverse(o.node, hightlightTextNode);
  1311 + function hightlightTextNode(textNode) {
  1312 + var match, patternNode, wrapperNode;
  1313 + if (match = regex.exec(textNode.data)) {
  1314 + wrapperNode = doc.createElement(o.tagName);
  1315 + o.className && (wrapperNode.className = o.className);
  1316 + patternNode = textNode.splitText(match.index);
  1317 + patternNode.splitText(match[0].length);
  1318 + wrapperNode.appendChild(patternNode.cloneNode(true));
  1319 + textNode.parentNode.replaceChild(wrapperNode, patternNode);
  1320 + }
  1321 + return !!match;
  1322 + }
  1323 + function traverse(el, hightlightTextNode) {
  1324 + var childNode, TEXT_NODE_TYPE = 3;
  1325 + for (var i = 0; i < el.childNodes.length; i++) {
  1326 + childNode = el.childNodes[i];
  1327 + if (childNode.nodeType === TEXT_NODE_TYPE) {
  1328 + i += hightlightTextNode(childNode) ? 1 : 0;
  1329 + } else {
  1330 + traverse(childNode, hightlightTextNode);
  1331 + }
  1332 + }
  1333 + }
  1334 + };
  1335 + function getRegex(patterns, caseSensitive, wordsOnly) {
  1336 + var escapedPatterns = [], regexStr;
  1337 + for (var i = 0, len = patterns.length; i < len; i++) {
  1338 + escapedPatterns.push(_.escapeRegExChars(patterns[i]));
  1339 + }
  1340 + regexStr = wordsOnly ? "\\b(" + escapedPatterns.join("|") + ")\\b" : "(" + escapedPatterns.join("|") + ")";
  1341 + return caseSensitive ? new RegExp(regexStr) : new RegExp(regexStr, "i");
  1342 + }
  1343 + }(window.document);
  1344 + var Input = function() {
  1345 + "use strict";
  1346 + var specialKeyCodeMap;
  1347 + specialKeyCodeMap = {
  1348 + 9: "tab",
  1349 + 27: "esc",
  1350 + 37: "left",
  1351 + 39: "right",
  1352 + 13: "enter",
  1353 + 38: "up",
  1354 + 40: "down"
  1355 + };
  1356 + function Input(o, www) {
  1357 + o = o || {};
  1358 + if (!o.input) {
  1359 + $.error("input is missing");
  1360 + }
  1361 + www.mixin(this);
  1362 + this.$hint = $(o.hint);
  1363 + this.$input = $(o.input);
  1364 + this.query = this.$input.val();
  1365 + this.queryWhenFocused = this.hasFocus() ? this.query : null;
  1366 + this.$overflowHelper = buildOverflowHelper(this.$input);
  1367 + this._checkLanguageDirection();
  1368 + if (this.$hint.length === 0) {
  1369 + this.setHint = this.getHint = this.clearHint = this.clearHintIfInvalid = _.noop;
  1370 + }
  1371 + }
  1372 + Input.normalizeQuery = function(str) {
  1373 + return _.toStr(str).replace(/^\s*/g, "").replace(/\s{2,}/g, " ");
  1374 + };
  1375 + _.mixin(Input.prototype, EventEmitter, {
  1376 + _onBlur: function onBlur() {
  1377 + this.resetInputValue();
  1378 + this.trigger("blurred");
  1379 + },
  1380 + _onFocus: function onFocus() {
  1381 + this.queryWhenFocused = this.query;
  1382 + this.trigger("focused");
  1383 + },
  1384 + _onKeydown: function onKeydown($e) {
  1385 + var keyName = specialKeyCodeMap[$e.which || $e.keyCode];
  1386 + this._managePreventDefault(keyName, $e);
  1387 + if (keyName && this._shouldTrigger(keyName, $e)) {
  1388 + this.trigger(keyName + "Keyed", $e);
  1389 + }
  1390 + },
  1391 + _onInput: function onInput() {
  1392 + this._setQuery(this.getInputValue());
  1393 + this.clearHintIfInvalid();
  1394 + this._checkLanguageDirection();
  1395 + },
  1396 + _managePreventDefault: function managePreventDefault(keyName, $e) {
  1397 + var preventDefault;
  1398 + switch (keyName) {
  1399 + case "up":
  1400 + case "down":
  1401 + preventDefault = !withModifier($e);
  1402 + break;
  1403 +
  1404 + default:
  1405 + preventDefault = false;
  1406 + }
  1407 + preventDefault && $e.preventDefault();
  1408 + },
  1409 + _shouldTrigger: function shouldTrigger(keyName, $e) {
  1410 + var trigger;
  1411 + switch (keyName) {
  1412 + case "tab":
  1413 + trigger = !withModifier($e);
  1414 + break;
  1415 +
  1416 + default:
  1417 + trigger = true;
  1418 + }
  1419 + return trigger;
  1420 + },
  1421 + _checkLanguageDirection: function checkLanguageDirection() {
  1422 + var dir = (this.$input.css("direction") || "ltr").toLowerCase();
  1423 + if (this.dir !== dir) {
  1424 + this.dir = dir;
  1425 + this.$hint.attr("dir", dir);
  1426 + this.trigger("langDirChanged", dir);
  1427 + }
  1428 + },
  1429 + _setQuery: function setQuery(val, silent) {
  1430 + var areEquivalent, hasDifferentWhitespace;
  1431 + areEquivalent = areQueriesEquivalent(val, this.query);
  1432 + hasDifferentWhitespace = areEquivalent ? this.query.length !== val.length : false;
  1433 + this.query = val;
  1434 + if (!silent && !areEquivalent) {
  1435 + this.trigger("queryChanged", this.query);
  1436 + } else if (!silent && hasDifferentWhitespace) {
  1437 + this.trigger("whitespaceChanged", this.query);
  1438 + }
  1439 + },
  1440 + bind: function() {
  1441 + var that = this, onBlur, onFocus, onKeydown, onInput;
  1442 + onBlur = _.bind(this._onBlur, this);
  1443 + onFocus = _.bind(this._onFocus, this);
  1444 + onKeydown = _.bind(this._onKeydown, this);
  1445 + onInput = _.bind(this._onInput, this);
  1446 + this.$input.on("blur.tt", onBlur).on("focus.tt", onFocus).on("keydown.tt", onKeydown);
  1447 + if (!_.isMsie() || _.isMsie() > 9) {
  1448 + this.$input.on("input.tt", onInput);
  1449 + } else {
  1450 + this.$input.on("keydown.tt keypress.tt cut.tt paste.tt", function($e) {
  1451 + if (specialKeyCodeMap[$e.which || $e.keyCode]) {
  1452 + return;
  1453 + }
  1454 + _.defer(_.bind(that._onInput, that, $e));
  1455 + });
  1456 + }
  1457 + return this;
  1458 + },
  1459 + focus: function focus() {
  1460 + this.$input.focus();
  1461 + },
  1462 + blur: function blur() {
  1463 + this.$input.blur();
  1464 + },
  1465 + getLangDir: function getLangDir() {
  1466 + return this.dir;
  1467 + },
  1468 + getQuery: function getQuery() {
  1469 + return this.query || "";
  1470 + },
  1471 + setQuery: function setQuery(val, silent) {
  1472 + this.setInputValue(val);
  1473 + this._setQuery(val, silent);
  1474 + },
  1475 + hasQueryChangedSinceLastFocus: function hasQueryChangedSinceLastFocus() {
  1476 + return this.query !== this.queryWhenFocused;
  1477 + },
  1478 + getInputValue: function getInputValue() {
  1479 + return this.$input.val();
  1480 + },
  1481 + setInputValue: function setInputValue(value) {
  1482 + this.$input.val(value);
  1483 + this.clearHintIfInvalid();
  1484 + this._checkLanguageDirection();
  1485 + },
  1486 + resetInputValue: function resetInputValue() {
  1487 + this.setInputValue(this.query);
  1488 + },
  1489 + getHint: function getHint() {
  1490 + return this.$hint.val();
  1491 + },
  1492 + setHint: function setHint(value) {
  1493 + this.$hint.val(value);
  1494 + },
  1495 + clearHint: function clearHint() {
  1496 + this.setHint("");
  1497 + },
  1498 + clearHintIfInvalid: function clearHintIfInvalid() {
  1499 + var val, hint, valIsPrefixOfHint, isValid;
  1500 + val = this.getInputValue();
  1501 + hint = this.getHint();
  1502 + valIsPrefixOfHint = val !== hint && hint.indexOf(val) === 0;
  1503 + isValid = val !== "" && valIsPrefixOfHint && !this.hasOverflow();
  1504 + !isValid && this.clearHint();
  1505 + },
  1506 + hasFocus: function hasFocus() {
  1507 + return this.$input.is(":focus");
  1508 + },
  1509 + hasOverflow: function hasOverflow() {
  1510 + var constraint = this.$input.width() - 2;
  1511 + this.$overflowHelper.text(this.getInputValue());
  1512 + return this.$overflowHelper.width() >= constraint;
  1513 + },
  1514 + isCursorAtEnd: function() {
  1515 + var valueLength, selectionStart, range;
  1516 + valueLength = this.$input.val().length;
  1517 + selectionStart = this.$input[0].selectionStart;
  1518 + if (_.isNumber(selectionStart)) {
  1519 + return selectionStart === valueLength;
  1520 + } else if (document.selection) {
  1521 + range = document.selection.createRange();
  1522 + range.moveStart("character", -valueLength);
  1523 + return valueLength === range.text.length;
  1524 + }
  1525 + return true;
  1526 + },
  1527 + destroy: function destroy() {
  1528 + this.$hint.off(".tt");
  1529 + this.$input.off(".tt");
  1530 + this.$overflowHelper.remove();
  1531 + this.$hint = this.$input = this.$overflowHelper = $("<div>");
  1532 + }
  1533 + });
  1534 + return Input;
  1535 + function buildOverflowHelper($input) {
  1536 + return $('<pre aria-hidden="true"></pre>').css({
  1537 + position: "absolute",
  1538 + visibility: "hidden",
  1539 + whiteSpace: "pre",
  1540 + fontFamily: $input.css("font-family"),
  1541 + fontSize: $input.css("font-size"),
  1542 + fontStyle: $input.css("font-style"),
  1543 + fontVariant: $input.css("font-variant"),
  1544 + fontWeight: $input.css("font-weight"),
  1545 + wordSpacing: $input.css("word-spacing"),
  1546 + letterSpacing: $input.css("letter-spacing"),
  1547 + textIndent: $input.css("text-indent"),
  1548 + textRendering: $input.css("text-rendering"),
  1549 + textTransform: $input.css("text-transform")
  1550 + }).insertAfter($input);
  1551 + }
  1552 + function areQueriesEquivalent(a, b) {
  1553 + return Input.normalizeQuery(a) === Input.normalizeQuery(b);
  1554 + }
  1555 + function withModifier($e) {
  1556 + return $e.altKey || $e.ctrlKey || $e.metaKey || $e.shiftKey;
  1557 + }
  1558 + }();
  1559 + var Dataset = function() {
  1560 + "use strict";
  1561 + var keys, nameGenerator;
  1562 + keys = {
  1563 + val: "tt-selectable-display",
  1564 + obj: "tt-selectable-object"
  1565 + };
  1566 + nameGenerator = _.getIdGenerator();
  1567 + function Dataset(o, www) {
  1568 + o = o || {};
  1569 + o.templates = o.templates || {};
  1570 + o.templates.notFound = o.templates.notFound || o.templates.empty;
  1571 + if (!o.source) {
  1572 + $.error("missing source");
  1573 + }
  1574 + if (!o.node) {
  1575 + $.error("missing node");
  1576 + }
  1577 + if (o.name && !isValidName(o.name)) {
  1578 + $.error("invalid dataset name: " + o.name);
  1579 + }
  1580 + www.mixin(this);
  1581 + this.highlight = !!o.highlight;
  1582 + this.name = o.name || nameGenerator();
  1583 + this.limit = o.limit || 5;
  1584 + this.displayFn = getDisplayFn(o.display || o.displayKey);
  1585 + this.templates = getTemplates(o.templates, this.displayFn);
  1586 + this.source = o.source.__ttAdapter ? o.source.__ttAdapter() : o.source;
  1587 + this.async = _.isUndefined(o.async) ? this.source.length > 2 : !!o.async;
  1588 + this._resetLastSuggestion();
  1589 + this.$el = $(o.node).addClass(this.classes.dataset).addClass(this.classes.dataset + "-" + this.name);
  1590 + }
  1591 + Dataset.extractData = function extractData(el) {
  1592 + var $el = $(el);
  1593 + if ($el.data(keys.obj)) {
  1594 + return {
  1595 + val: $el.data(keys.val) || "",
  1596 + obj: $el.data(keys.obj) || null
  1597 + };
  1598 + }
  1599 + return null;
  1600 + };
  1601 + _.mixin(Dataset.prototype, EventEmitter, {
  1602 + _overwrite: function overwrite(query, suggestions) {
  1603 + suggestions = suggestions || [];
  1604 + if (suggestions.length) {
  1605 + this._renderSuggestions(query, suggestions);
  1606 + } else if (this.async && this.templates.pending) {
  1607 + this._renderPending(query);
  1608 + } else if (!this.async && this.templates.notFound) {
  1609 + this._renderNotFound(query);
  1610 + } else {
  1611 + this._empty();
  1612 + }
  1613 + this.trigger("rendered", this.name, suggestions, false);
  1614 + },
  1615 + _append: function append(query, suggestions) {
  1616 + suggestions = suggestions || [];
  1617 + if (suggestions.length && this.$lastSuggestion.length) {
  1618 + this._appendSuggestions(query, suggestions);
  1619 + } else if (suggestions.length) {
  1620 + this._renderSuggestions(query, suggestions);
  1621 + } else if (!this.$lastSuggestion.length && this.templates.notFound) {
  1622 + this._renderNotFound(query);
  1623 + }
  1624 + this.trigger("rendered", this.name, suggestions, true);
  1625 + },
  1626 + _renderSuggestions: function renderSuggestions(query, suggestions) {
  1627 + var $fragment;
  1628 + $fragment = this._getSuggestionsFragment(query, suggestions);
  1629 + this.$lastSuggestion = $fragment.children().last();
  1630 + this.$el.html($fragment).prepend(this._getHeader(query, suggestions)).append(this._getFooter(query, suggestions));
  1631 + },
  1632 + _appendSuggestions: function appendSuggestions(query, suggestions) {
  1633 + var $fragment, $lastSuggestion;
  1634 + $fragment = this._getSuggestionsFragment(query, suggestions);
  1635 + $lastSuggestion = $fragment.children().last();
  1636 + this.$lastSuggestion.after($fragment);
  1637 + this.$lastSuggestion = $lastSuggestion;
  1638 + },
  1639 + _renderPending: function renderPending(query) {
  1640 + var template = this.templates.pending;
  1641 + this._resetLastSuggestion();
  1642 + template && this.$el.html(template({
  1643 + query: query,
  1644 + dataset: this.name
  1645 + }));
  1646 + },
  1647 + _renderNotFound: function renderNotFound(query) {
  1648 + var template = this.templates.notFound;
  1649 + this._resetLastSuggestion();
  1650 + template && this.$el.html(template({
  1651 + query: query,
  1652 + dataset: this.name
  1653 + }));
  1654 + },
  1655 + _empty: function empty() {
  1656 + this.$el.empty();
  1657 + this._resetLastSuggestion();
  1658 + },
  1659 + _getSuggestionsFragment: function getSuggestionsFragment(query, suggestions) {
  1660 + var that = this, fragment;
  1661 + fragment = document.createDocumentFragment();
  1662 + _.each(suggestions, function getSuggestionNode(suggestion) {
  1663 + var $el, context;
  1664 + context = that._injectQuery(query, suggestion);
  1665 + $el = $(that.templates.suggestion(context)).data(keys.obj, suggestion).data(keys.val, that.displayFn(suggestion)).addClass(that.classes.suggestion + " " + that.classes.selectable);
  1666 + fragment.appendChild($el[0]);
  1667 + });
  1668 + this.highlight && highlight({
  1669 + className: this.classes.highlight,
  1670 + node: fragment,
  1671 + pattern: query
  1672 + });
  1673 + return $(fragment);
  1674 + },
  1675 + _getFooter: function getFooter(query, suggestions) {
  1676 + return this.templates.footer ? this.templates.footer({
  1677 + query: query,
  1678 + suggestions: suggestions,
  1679 + dataset: this.name
  1680 + }) : null;
  1681 + },
  1682 + _getHeader: function getHeader(query, suggestions) {
  1683 + return this.templates.header ? this.templates.header({
  1684 + query: query,
  1685 + suggestions: suggestions,
  1686 + dataset: this.name
  1687 + }) : null;
  1688 + },
  1689 + _resetLastSuggestion: function resetLastSuggestion() {
  1690 + this.$lastSuggestion = $();
  1691 + },
  1692 + _injectQuery: function injectQuery(query, obj) {
  1693 + return _.isObject(obj) ? _.mixin({
  1694 + _query: query
  1695 + }, obj) : obj;
  1696 + },
  1697 + update: function update(query) {
  1698 + var that = this, canceled = false, syncCalled = false, rendered = 0;
  1699 + this.cancel();
  1700 + this.cancel = function cancel() {
  1701 + canceled = true;
  1702 + that.cancel = $.noop;
  1703 + that.async && that.trigger("asyncCanceled", query);
  1704 + };
  1705 + this.source(query, sync, async);
  1706 + !syncCalled && sync([]);
  1707 + function sync(suggestions) {
  1708 + if (syncCalled) {
  1709 + return;
  1710 + }
  1711 + syncCalled = true;
  1712 + suggestions = (suggestions || []).slice(0, that.limit);
  1713 + rendered = suggestions.length;
  1714 + that._overwrite(query, suggestions);
  1715 + if (rendered < that.limit && that.async) {
  1716 + that.trigger("asyncRequested", query);
  1717 + }
  1718 + }
  1719 + function async(suggestions) {
  1720 + suggestions = suggestions || [];
  1721 + if (!canceled && rendered < that.limit) {
  1722 + that.cancel = $.noop;
  1723 + rendered += suggestions.length;
  1724 + that._append(query, suggestions.slice(0, that.limit - rendered));
  1725 + that.async && that.trigger("asyncReceived", query);
  1726 + }
  1727 + }
  1728 + },
  1729 + cancel: $.noop,
  1730 + clear: function clear() {
  1731 + this._empty();
  1732 + this.cancel();
  1733 + this.trigger("cleared");
  1734 + },
  1735 + isEmpty: function isEmpty() {
  1736 + return this.$el.is(":empty");
  1737 + },
  1738 + destroy: function destroy() {
  1739 + this.$el = $("<div>");
  1740 + }
  1741 + });
  1742 + return Dataset;
  1743 + function getDisplayFn(display) {
  1744 + display = display || _.stringify;
  1745 + return _.isFunction(display) ? display : displayFn;
  1746 + function displayFn(obj) {
  1747 + return obj[display];
  1748 + }
  1749 + }
  1750 + function getTemplates(templates, displayFn) {
  1751 + return {
  1752 + notFound: templates.notFound && _.templatify(templates.notFound),
  1753 + pending: templates.pending && _.templatify(templates.pending),
  1754 + header: templates.header && _.templatify(templates.header),
  1755 + footer: templates.footer && _.templatify(templates.footer),
  1756 + suggestion: templates.suggestion || suggestionTemplate
  1757 + };
  1758 + function suggestionTemplate(context) {
  1759 + return $("<div>").text(displayFn(context));
  1760 + }
  1761 + }
  1762 + function isValidName(str) {
  1763 + return /^[_a-zA-Z0-9-]+$/.test(str);
  1764 + }
  1765 + }();
  1766 + var Menu = function() {
  1767 + "use strict";
  1768 + function Menu(o, www) {
  1769 + var that = this;
  1770 + o = o || {};
  1771 + if (!o.node) {
  1772 + $.error("node is required");
  1773 + }
  1774 + www.mixin(this);
  1775 + this.$node = $(o.node);
  1776 + this.query = null;
  1777 + this.datasets = _.map(o.datasets, initializeDataset);
  1778 + function initializeDataset(oDataset) {
  1779 + var node = that.$node.find(oDataset.node).first();
  1780 + oDataset.node = node.length ? node : $("<div>").appendTo(that.$node);
  1781 + return new Dataset(oDataset, www);
  1782 + }
  1783 + }
  1784 + _.mixin(Menu.prototype, EventEmitter, {
  1785 + _onSelectableClick: function onSelectableClick($e) {
  1786 + this.trigger("selectableClicked", $($e.currentTarget));
  1787 + },
  1788 + _onRendered: function onRendered(type, dataset, suggestions, async) {
  1789 + this.$node.toggleClass(this.classes.empty, this._allDatasetsEmpty());
  1790 + this.trigger("datasetRendered", dataset, suggestions, async);
  1791 + },
  1792 + _onCleared: function onCleared() {
  1793 + this.$node.toggleClass(this.classes.empty, this._allDatasetsEmpty());
  1794 + this.trigger("datasetCleared");
  1795 + },
  1796 + _propagate: function propagate() {
  1797 + this.trigger.apply(this, arguments);
  1798 + },
  1799 + _allDatasetsEmpty: function allDatasetsEmpty() {
  1800 + return _.every(this.datasets, isDatasetEmpty);
  1801 + function isDatasetEmpty(dataset) {
  1802 + return dataset.isEmpty();
  1803 + }
  1804 + },
  1805 + _getSelectables: function getSelectables() {
  1806 + return this.$node.find(this.selectors.selectable);
  1807 + },
  1808 + _removeCursor: function _removeCursor() {
  1809 + var $selectable = this.getActiveSelectable();
  1810 + $selectable && $selectable.removeClass(this.classes.cursor);
  1811 + },
  1812 + _ensureVisible: function ensureVisible($el) {
  1813 + var elTop, elBottom, nodeScrollTop, nodeHeight;
  1814 + elTop = $el.position().top;
  1815 + elBottom = elTop + $el.outerHeight(true);
  1816 + nodeScrollTop = this.$node.scrollTop();
  1817 + nodeHeight = this.$node.height() + parseInt(this.$node.css("paddingTop"), 10) + parseInt(this.$node.css("paddingBottom"), 10);
  1818 + if (elTop < 0) {
  1819 + this.$node.scrollTop(nodeScrollTop + elTop);
  1820 + } else if (nodeHeight < elBottom) {
  1821 + this.$node.scrollTop(nodeScrollTop + (elBottom - nodeHeight));
  1822 + }
  1823 + },
  1824 + bind: function() {
  1825 + var that = this, onSelectableClick;
  1826 + onSelectableClick = _.bind(this._onSelectableClick, this);
  1827 + this.$node.on("click.tt", this.selectors.selectable, onSelectableClick);
  1828 + _.each(this.datasets, function(dataset) {
  1829 + dataset.onSync("asyncRequested", that._propagate, that).onSync("asyncCanceled", that._propagate, that).onSync("asyncReceived", that._propagate, that).onSync("rendered", that._onRendered, that).onSync("cleared", that._onCleared, that);
  1830 + });
  1831 + return this;
  1832 + },
  1833 + isOpen: function isOpen() {
  1834 + return this.$node.hasClass(this.classes.open);
  1835 + },
  1836 + open: function open() {
  1837 + this.$node.addClass(this.classes.open);
  1838 + },
  1839 + close: function close() {
  1840 + this.$node.removeClass(this.classes.open);
  1841 + this._removeCursor();
  1842 + },
  1843 + setLanguageDirection: function setLanguageDirection(dir) {
  1844 + this.$node.attr("dir", dir);
  1845 + },
  1846 + selectableRelativeToCursor: function selectableRelativeToCursor(delta) {
  1847 + var $selectables, $oldCursor, oldIndex, newIndex;
  1848 + $oldCursor = this.getActiveSelectable();
  1849 + $selectables = this._getSelectables();
  1850 + oldIndex = $oldCursor ? $selectables.index($oldCursor) : -1;
  1851 + newIndex = oldIndex + delta;
  1852 + newIndex = (newIndex + 1) % ($selectables.length + 1) - 1;
  1853 + newIndex = newIndex < -1 ? $selectables.length - 1 : newIndex;
  1854 + return newIndex === -1 ? null : $selectables.eq(newIndex);
  1855 + },
  1856 + setCursor: function setCursor($selectable) {
  1857 + this._removeCursor();
  1858 + if ($selectable = $selectable && $selectable.first()) {
  1859 + $selectable.addClass(this.classes.cursor);
  1860 + this._ensureVisible($selectable);
  1861 + }
  1862 + },
  1863 + getSelectableData: function getSelectableData($el) {
  1864 + return $el && $el.length ? Dataset.extractData($el) : null;
  1865 + },
  1866 + getActiveSelectable: function getActiveSelectable() {
  1867 + var $selectable = this._getSelectables().filter(this.selectors.cursor).first();
  1868 + return $selectable.length ? $selectable : null;
  1869 + },
  1870 + getTopSelectable: function getTopSelectable() {
  1871 + var $selectable = this._getSelectables().first();
  1872 + return $selectable.length ? $selectable : null;
  1873 + },
  1874 + update: function update(query) {
  1875 + var isValidUpdate = query !== this.query;
  1876 + if (isValidUpdate) {
  1877 + this.query = query;
  1878 + _.each(this.datasets, updateDataset);
  1879 + }
  1880 + return isValidUpdate;
  1881 + function updateDataset(dataset) {
  1882 + dataset.update(query);
  1883 + }
  1884 + },
  1885 + empty: function empty() {
  1886 + _.each(this.datasets, clearDataset);
  1887 + this.query = null;
  1888 + this.$node.addClass(this.classes.empty);
  1889 + function clearDataset(dataset) {
  1890 + dataset.clear();
  1891 + }
  1892 + },
  1893 + destroy: function destroy() {
  1894 + this.$node.off(".tt");
  1895 + this.$node = $("<div>");
  1896 + _.each(this.datasets, destroyDataset);
  1897 + function destroyDataset(dataset) {
  1898 + dataset.destroy();
  1899 + }
  1900 + }
  1901 + });
  1902 + return Menu;
  1903 + }();
  1904 + var DefaultMenu = function() {
  1905 + "use strict";
  1906 + var s = Menu.prototype;
  1907 + function DefaultMenu() {
  1908 + Menu.apply(this, [].slice.call(arguments, 0));
  1909 + }
  1910 + _.mixin(DefaultMenu.prototype, Menu.prototype, {
  1911 + open: function open() {
  1912 + !this._allDatasetsEmpty() && this._show();
  1913 + return s.open.apply(this, [].slice.call(arguments, 0));
  1914 + },
  1915 + close: function close() {
  1916 + this._hide();
  1917 + return s.close.apply(this, [].slice.call(arguments, 0));
  1918 + },
  1919 + _onRendered: function onRendered() {
  1920 + if (this._allDatasetsEmpty()) {
  1921 + this._hide();
  1922 + } else {
  1923 + this.isOpen() && this._show();
  1924 + }
  1925 + return s._onRendered.apply(this, [].slice.call(arguments, 0));
  1926 + },
  1927 + _onCleared: function onCleared() {
  1928 + if (this._allDatasetsEmpty()) {
  1929 + this._hide();
  1930 + } else {
  1931 + this.isOpen() && this._show();
  1932 + }
  1933 + return s._onCleared.apply(this, [].slice.call(arguments, 0));
  1934 + },
  1935 + setLanguageDirection: function setLanguageDirection(dir) {
  1936 + this.$node.css(dir === "ltr" ? this.css.ltr : this.css.rtl);
  1937 + return s.setLanguageDirection.apply(this, [].slice.call(arguments, 0));
  1938 + },
  1939 + _hide: function hide() {
  1940 + this.$node.hide();
  1941 + },
  1942 + _show: function show() {
  1943 + this.$node.css("display", "block");
  1944 + }
  1945 + });
  1946 + return DefaultMenu;
  1947 + }();
  1948 + var Typeahead = function() {
  1949 + "use strict";
  1950 + function Typeahead(o, www) {
  1951 + var onFocused, onBlurred, onEnterKeyed, onTabKeyed, onEscKeyed, onUpKeyed, onDownKeyed, onLeftKeyed, onRightKeyed, onQueryChanged, onWhitespaceChanged;
  1952 + o = o || {};
  1953 + if (!o.input) {
  1954 + $.error("missing input");
  1955 + }
  1956 + if (!o.menu) {
  1957 + $.error("missing menu");
  1958 + }
  1959 + if (!o.eventBus) {
  1960 + $.error("missing event bus");
  1961 + }
  1962 + www.mixin(this);
  1963 + this.eventBus = o.eventBus;
  1964 + this.minLength = _.isNumber(o.minLength) ? o.minLength : 1;
  1965 + this.input = o.input;
  1966 + this.menu = o.menu;
  1967 + this.enabled = true;
  1968 + this.active = false;
  1969 + this.input.hasFocus() && this.activate();
  1970 + this.dir = this.input.getLangDir();
  1971 + this._hacks();
  1972 + this.menu.bind().onSync("selectableClicked", this._onSelectableClicked, this).onSync("asyncRequested", this._onAsyncRequested, this).onSync("asyncCanceled", this._onAsyncCanceled, this).onSync("asyncReceived", this._onAsyncReceived, this).onSync("datasetRendered", this._onDatasetRendered, this).onSync("datasetCleared", this._onDatasetCleared, this);
  1973 + onFocused = c(this, "activate", "open", "_onFocused");
  1974 + onBlurred = c(this, "deactivate", "_onBlurred");
  1975 + onEnterKeyed = c(this, "isActive", "isOpen", "_onEnterKeyed");
  1976 + onTabKeyed = c(this, "isActive", "isOpen", "_onTabKeyed");
  1977 + onEscKeyed = c(this, "isActive", "_onEscKeyed");
  1978 + onUpKeyed = c(this, "isActive", "open", "_onUpKeyed");
  1979 + onDownKeyed = c(this, "isActive", "open", "_onDownKeyed");
  1980 + onLeftKeyed = c(this, "isActive", "isOpen", "_onLeftKeyed");
  1981 + onRightKeyed = c(this, "isActive", "isOpen", "_onRightKeyed");
  1982 + onQueryChanged = c(this, "_openIfActive", "_onQueryChanged");
  1983 + onWhitespaceChanged = c(this, "_openIfActive", "_onWhitespaceChanged");
  1984 + this.input.bind().onSync("focused", onFocused, this).onSync("blurred", onBlurred, this).onSync("enterKeyed", onEnterKeyed, this).onSync("tabKeyed", onTabKeyed, this).onSync("escKeyed", onEscKeyed, this).onSync("upKeyed", onUpKeyed, this).onSync("downKeyed", onDownKeyed, this).onSync("leftKeyed", onLeftKeyed, this).onSync("rightKeyed", onRightKeyed, this).onSync("queryChanged", onQueryChanged, this).onSync("whitespaceChanged", onWhitespaceChanged, this).onSync("langDirChanged", this._onLangDirChanged, this);
  1985 + }
  1986 + _.mixin(Typeahead.prototype, {
  1987 + _hacks: function hacks() {
  1988 + var $input, $menu;
  1989 + $input = this.input.$input || $("<div>");
  1990 + $menu = this.menu.$node || $("<div>");
  1991 + $input.on("blur.tt", function($e) {
  1992 + var active, isActive, hasActive;
  1993 + active = document.activeElement;
  1994 + isActive = $menu.is(active);
  1995 + hasActive = $menu.has(active).length > 0;
  1996 + if (_.isMsie() && (isActive || hasActive)) {
  1997 + $e.preventDefault();
  1998 + $e.stopImmediatePropagation();
  1999 + _.defer(function() {
  2000 + $input.focus();
  2001 + });
  2002 + }
  2003 + });
  2004 + $menu.on("mousedown.tt", function($e) {
  2005 + $e.preventDefault();
  2006 + });
  2007 + },
  2008 + _onSelectableClicked: function onSelectableClicked(type, $el) {
  2009 + this.select($el);
  2010 + },
  2011 + _onDatasetCleared: function onDatasetCleared() {
  2012 + this._updateHint();
  2013 + },
  2014 + _onDatasetRendered: function onDatasetRendered(type, dataset, suggestions, async) {
  2015 + this._updateHint();
  2016 + this.eventBus.trigger("render", suggestions, async, dataset);
  2017 + },
  2018 + _onAsyncRequested: function onAsyncRequested(type, dataset, query) {
  2019 + this.eventBus.trigger("asyncrequest", query, dataset);
  2020 + },
  2021 + _onAsyncCanceled: function onAsyncCanceled(type, dataset, query) {
  2022 + this.eventBus.trigger("asynccancel", query, dataset);
  2023 + },
  2024 + _onAsyncReceived: function onAsyncReceived(type, dataset, query) {
  2025 + this.eventBus.trigger("asyncreceive", query, dataset);
  2026 + },
  2027 + _onFocused: function onFocused() {
  2028 + this._minLengthMet() && this.menu.update(this.input.getQuery());
  2029 + },
  2030 + _onBlurred: function onBlurred() {
  2031 + if (this.input.hasQueryChangedSinceLastFocus()) {
  2032 + this.eventBus.trigger("change", this.input.getQuery());
  2033 + }
  2034 + },
  2035 + _onEnterKeyed: function onEnterKeyed(type, $e) {
  2036 + var $selectable;
  2037 + if ($selectable = this.menu.getActiveSelectable()) {
  2038 + this.select($selectable) && $e.preventDefault();
  2039 + }
  2040 + },
  2041 + _onTabKeyed: function onTabKeyed(type, $e) {
  2042 + var $selectable;
  2043 + if ($selectable = this.menu.getActiveSelectable()) {
  2044 + this.select($selectable) && $e.preventDefault();
  2045 + } else if ($selectable = this.menu.getTopSelectable()) {
  2046 + this.autocomplete($selectable) && $e.preventDefault();
  2047 + }
  2048 + },
  2049 + _onEscKeyed: function onEscKeyed() {
  2050 + this.close();
  2051 + },
  2052 + _onUpKeyed: function onUpKeyed() {
  2053 + this.moveCursor(-1);
  2054 + },
  2055 + _onDownKeyed: function onDownKeyed() {
  2056 + this.moveCursor(+1);
  2057 + },
  2058 + _onLeftKeyed: function onLeftKeyed() {
  2059 + if (this.dir === "rtl" && this.input.isCursorAtEnd()) {
  2060 + this.autocomplete(this.menu.getTopSelectable());
  2061 + }
  2062 + },
  2063 + _onRightKeyed: function onRightKeyed() {
  2064 + if (this.dir === "ltr" && this.input.isCursorAtEnd()) {
  2065 + this.autocomplete(this.menu.getTopSelectable());
  2066 + }
  2067 + },
  2068 + _onQueryChanged: function onQueryChanged(e, query) {
  2069 + this._minLengthMet(query) ? this.menu.update(query) : this.menu.empty();
  2070 + },
  2071 + _onWhitespaceChanged: function onWhitespaceChanged() {
  2072 + this._updateHint();
  2073 + },
  2074 + _onLangDirChanged: function onLangDirChanged(e, dir) {
  2075 + if (this.dir !== dir) {
  2076 + this.dir = dir;
  2077 + this.menu.setLanguageDirection(dir);
  2078 + }
  2079 + },
  2080 + _openIfActive: function openIfActive() {
  2081 + this.isActive() && this.open();
  2082 + },
  2083 + _minLengthMet: function minLengthMet(query) {
  2084 + query = _.isString(query) ? query : this.input.getQuery() || "";
  2085 + return query.length >= this.minLength;
  2086 + },
  2087 + _updateHint: function updateHint() {
  2088 + var $selectable, data, val, query, escapedQuery, frontMatchRegEx, match;
  2089 + $selectable = this.menu.getTopSelectable();
  2090 + data = this.menu.getSelectableData($selectable);
  2091 + val = this.input.getInputValue();
  2092 + if (data && !_.isBlankString(val) && !this.input.hasOverflow()) {
  2093 + query = Input.normalizeQuery(val);
  2094 + escapedQuery = _.escapeRegExChars(query);
  2095 + frontMatchRegEx = new RegExp("^(?:" + escapedQuery + ")(.+$)", "i");
  2096 + match = frontMatchRegEx.exec(data.val);
  2097 + match && this.input.setHint(val + match[1]);
  2098 + } else {
  2099 + this.input.clearHint();
  2100 + }
  2101 + },
  2102 + isEnabled: function isEnabled() {
  2103 + return this.enabled;
  2104 + },
  2105 + enable: function enable() {
  2106 + this.enabled = true;
  2107 + },
  2108 + disable: function disable() {
  2109 + this.enabled = false;
  2110 + },
  2111 + isActive: function isActive() {
  2112 + return this.active;
  2113 + },
  2114 + activate: function activate() {
  2115 + if (this.isActive()) {
  2116 + return true;
  2117 + } else if (!this.isEnabled() || this.eventBus.before("active")) {
  2118 + return false;
  2119 + } else {
  2120 + this.active = true;
  2121 + this.eventBus.trigger("active");
  2122 + return true;
  2123 + }
  2124 + },
  2125 + deactivate: function deactivate() {
  2126 + if (!this.isActive()) {
  2127 + return true;
  2128 + } else if (this.eventBus.before("idle")) {
  2129 + return false;
  2130 + } else {
  2131 + this.active = false;
  2132 + this.close();
  2133 + this.eventBus.trigger("idle");
  2134 + return true;
  2135 + }
  2136 + },
  2137 + isOpen: function isOpen() {
  2138 + return this.menu.isOpen();
  2139 + },
  2140 + open: function open() {
  2141 + if (!this.isOpen() && !this.eventBus.before("open")) {
  2142 + this.menu.open();
  2143 + this._updateHint();
  2144 + this.eventBus.trigger("open");
  2145 + }
  2146 + return this.isOpen();
  2147 + },
  2148 + close: function close() {
  2149 + if (this.isOpen() && !this.eventBus.before("close")) {
  2150 + this.menu.close();
  2151 + this.input.clearHint();
  2152 + this.input.resetInputValue();
  2153 + this.eventBus.trigger("close");
  2154 + }
  2155 + return !this.isOpen();
  2156 + },
  2157 + setVal: function setVal(val) {
  2158 + this.input.setQuery(_.toStr(val));
  2159 + },
  2160 + getVal: function getVal() {
  2161 + return this.input.getQuery();
  2162 + },
  2163 + select: function select($selectable) {
  2164 + var data = this.menu.getSelectableData($selectable);
  2165 + if (data && !this.eventBus.before("select", data.obj)) {
  2166 + this.input.setQuery(data.val, true);
  2167 + this.eventBus.trigger("select", data.obj);
  2168 + this.close();
  2169 + return true;
  2170 + }
  2171 + return false;
  2172 + },
  2173 + autocomplete: function autocomplete($selectable) {
  2174 + var query, data, isValid;
  2175 + query = this.input.getQuery();
  2176 + data = this.menu.getSelectableData($selectable);
  2177 + isValid = data && query !== data.val;
  2178 + if (isValid && !this.eventBus.before("autocomplete", data.obj)) {
  2179 + this.input.setQuery(data.val);
  2180 + this.eventBus.trigger("autocomplete", data.obj);
  2181 + return true;
  2182 + }
  2183 + return false;
  2184 + },
  2185 + moveCursor: function moveCursor(delta) {
  2186 + var query, $candidate, data, payload, cancelMove;
  2187 + query = this.input.getQuery();
  2188 + $candidate = this.menu.selectableRelativeToCursor(delta);
  2189 + data = this.menu.getSelectableData($candidate);
  2190 + payload = data ? data.obj : null;
  2191 + cancelMove = this._minLengthMet() && this.menu.update(query);
  2192 + if (!cancelMove && !this.eventBus.before("cursorchange", payload)) {
  2193 + this.menu.setCursor($candidate);
  2194 + if (data) {
  2195 + this.input.setInputValue(data.val);
  2196 + } else {
  2197 + this.input.resetInputValue();
  2198 + this._updateHint();
  2199 + }
  2200 + this.eventBus.trigger("cursorchange", payload);
  2201 + return true;
  2202 + }
  2203 + return false;
  2204 + },
  2205 + destroy: function destroy() {
  2206 + this.input.destroy();
  2207 + this.menu.destroy();
  2208 + }
  2209 + });
  2210 + return Typeahead;
  2211 + function c(ctx) {
  2212 + var methods = [].slice.call(arguments, 1);
  2213 + return function() {
  2214 + var args = [].slice.call(arguments);
  2215 + _.each(methods, function(method) {
  2216 + return ctx[method].apply(ctx, args);
  2217 + });
  2218 + };
  2219 + }
  2220 + }();
  2221 + (function() {
  2222 + "use strict";
  2223 + var old, keys, methods;
  2224 + old = $.fn.typeahead;
  2225 + keys = {
  2226 + www: "tt-www",
  2227 + attrs: "tt-attrs",
  2228 + typeahead: "tt-typeahead"
  2229 + };
  2230 + methods = {
  2231 + initialize: function initialize(o, datasets) {
  2232 + var www;
  2233 + datasets = _.isArray(datasets) ? datasets : [].slice.call(arguments, 1);
  2234 + o = o || {};
  2235 + www = WWW(o.classNames);
  2236 + return this.each(attach);
  2237 + function attach() {
  2238 + var $input, $wrapper, $hint, $menu, defaultHint, defaultMenu, eventBus, input, menu, typeahead, MenuConstructor;
  2239 + _.each(datasets, function(d) {
  2240 + d.highlight = !!o.highlight;
  2241 + });
  2242 + $input = $(this);
  2243 + $wrapper = $(www.html.wrapper);
  2244 + $hint = $elOrNull(o.hint);
  2245 + $menu = $elOrNull(o.menu);
  2246 + defaultHint = o.hint !== false && !$hint;
  2247 + defaultMenu = o.menu !== false && !$menu;
  2248 + defaultHint && ($hint = buildHintFromInput($input, www));
  2249 + defaultMenu && ($menu = $(www.html.menu).css(www.css.menu));
  2250 + $hint && $hint.val("");
  2251 + $input = prepInput($input, www);
  2252 + if (defaultHint || defaultMenu) {
  2253 + $wrapper.css(www.css.wrapper);
  2254 + $input.css(defaultHint ? www.css.input : www.css.inputWithNoHint);
  2255 + $input.wrap($wrapper).parent().prepend(defaultHint ? $hint : null).append(defaultMenu ? $menu : null);
  2256 + }
  2257 + MenuConstructor = defaultMenu ? DefaultMenu : Menu;
  2258 + eventBus = new EventBus({
  2259 + el: $input
  2260 + });
  2261 + input = new Input({
  2262 + hint: $hint,
  2263 + input: $input
  2264 + }, www);
  2265 + menu = new MenuConstructor({
  2266 + node: $menu,
  2267 + datasets: datasets
  2268 + }, www);
  2269 + typeahead = new Typeahead({
  2270 + input: input,
  2271 + menu: menu,
  2272 + eventBus: eventBus,
  2273 + minLength: o.minLength
  2274 + }, www);
  2275 + $input.data(keys.www, www);
  2276 + $input.data(keys.typeahead, typeahead);
  2277 + }
  2278 + },
  2279 + isEnabled: function isEnabled() {
  2280 + var enabled;
  2281 + ttEach(this.first(), function(t) {
  2282 + enabled = t.isEnabled();
  2283 + });
  2284 + return enabled;
  2285 + },
  2286 + enable: function enable() {
  2287 + ttEach(this, function(t) {
  2288 + t.enable();
  2289 + });
  2290 + return this;
  2291 + },
  2292 + disable: function disable() {
  2293 + ttEach(this, function(t) {
  2294 + t.disable();
  2295 + });
  2296 + return this;
  2297 + },
  2298 + isActive: function isActive() {
  2299 + var active;
  2300 + ttEach(this.first(), function(t) {
  2301 + active = t.isActive();
  2302 + });
  2303 + return active;
  2304 + },
  2305 + activate: function activate() {
  2306 + ttEach(this, function(t) {
  2307 + t.activate();
  2308 + });
  2309 + return this;
  2310 + },
  2311 + deactivate: function deactivate() {
  2312 + ttEach(this, function(t) {
  2313 + t.deactivate();
  2314 + });
  2315 + return this;
  2316 + },
  2317 + isOpen: function isOpen() {
  2318 + var open;
  2319 + ttEach(this.first(), function(t) {
  2320 + open = t.isOpen();
  2321 + });
  2322 + return open;
  2323 + },
  2324 + open: function open() {
  2325 + ttEach(this, function(t) {
  2326 + t.open();
  2327 + });
  2328 + return this;
  2329 + },
  2330 + close: function close() {
  2331 + ttEach(this, function(t) {
  2332 + t.close();
  2333 + });
  2334 + return this;
  2335 + },
  2336 + select: function select(el) {
  2337 + var success = false, $el = $(el);
  2338 + ttEach(this.first(), function(t) {
  2339 + success = t.select($el);
  2340 + });
  2341 + return success;
  2342 + },
  2343 + autocomplete: function autocomplete(el) {
  2344 + var success = false, $el = $(el);
  2345 + ttEach(this.first(), function(t) {
  2346 + success = t.autocomplete($el);
  2347 + });
  2348 + return success;
  2349 + },
  2350 + moveCursor: function moveCursoe(delta) {
  2351 + var success = false;
  2352 + ttEach(this.first(), function(t) {
  2353 + success = t.moveCursor(delta);
  2354 + });
  2355 + return success;
  2356 + },
  2357 + val: function val(newVal) {
  2358 + var query;
  2359 + if (!arguments.length) {
  2360 + ttEach(this.first(), function(t) {
  2361 + query = t.getVal();
  2362 + });
  2363 + return query;
  2364 + } else {
  2365 + ttEach(this, function(t) {
  2366 + t.setVal(newVal);
  2367 + });
  2368 + return this;
  2369 + }
  2370 + },
  2371 + destroy: function destroy() {
  2372 + ttEach(this, function(typeahead, $input) {
  2373 + revert($input);
  2374 + typeahead.destroy();
  2375 + });
  2376 + return this;
  2377 + }
  2378 + };
  2379 + $.fn.typeahead = function(method) {
  2380 + if (methods[method]) {
  2381 + return methods[method].apply(this, [].slice.call(arguments, 1));
  2382 + } else {
  2383 + return methods.initialize.apply(this, arguments);
  2384 + }
  2385 + };
  2386 + $.fn.typeahead.noConflict = function noConflict() {
  2387 + $.fn.typeahead = old;
  2388 + return this;
  2389 + };
  2390 + function ttEach($els, fn) {
  2391 + $els.each(function() {
  2392 + var $input = $(this), typeahead;
  2393 + (typeahead = $input.data(keys.typeahead)) && fn(typeahead, $input);
  2394 + });
  2395 + }
  2396 + function buildHintFromInput($input, www) {
  2397 + return $input.clone().addClass(www.classes.hint).removeData().css(www.css.hint).css(getBackgroundStyles($input)).prop("readonly", true).removeAttr("id name placeholder required").attr({
  2398 + autocomplete: "off",
  2399 + spellcheck: "false",
  2400 + tabindex: -1
  2401 + });
  2402 + }
  2403 + function prepInput($input, www) {
  2404 + $input.data(keys.attrs, {
  2405 + dir: $input.attr("dir"),
  2406 + autocomplete: $input.attr("autocomplete"),
  2407 + spellcheck: $input.attr("spellcheck"),
  2408 + style: $input.attr("style")
  2409 + });
  2410 + $input.addClass(www.classes.input).attr({
  2411 + autocomplete: "off",
  2412 + spellcheck: false
  2413 + });
  2414 + try {
  2415 + !$input.attr("dir") && $input.attr("dir", "auto");
  2416 + } catch (e) {}
  2417 + return $input;
  2418 + }
  2419 + function getBackgroundStyles($el) {
  2420 + return {
  2421 + backgroundAttachment: $el.css("background-attachment"),
  2422 + backgroundClip: $el.css("background-clip"),
  2423 + backgroundColor: $el.css("background-color"),
  2424 + backgroundImage: $el.css("background-image"),
  2425 + backgroundOrigin: $el.css("background-origin"),
  2426 + backgroundPosition: $el.css("background-position"),
  2427 + backgroundRepeat: $el.css("background-repeat"),
  2428 + backgroundSize: $el.css("background-size")
  2429 + };
  2430 + }
  2431 + function revert($input) {
  2432 + var www, $wrapper;
  2433 + www = $input.data(keys.www);
  2434 + $wrapper = $input.parent().filter(www.selectors.wrapper);
  2435 + _.each($input.data(keys.attrs), function(val, key) {
  2436 + _.isUndefined(val) ? $input.removeAttr(key) : $input.attr(key, val);
  2437 + });
  2438 + $input.removeData(keys.typeahead).removeData(keys.www).removeData(keys.attr).removeClass(www.classes.input);
  2439 + if ($wrapper.length) {
  2440 + $input.detach().insertAfter($wrapper);
  2441 + $wrapper.remove();
  2442 + }
  2443 + }
  2444 + function $elOrNull(obj) {
  2445 + var isValid, $el;
  2446 + isValid = _.isJQuery(obj) || _.isElement(obj);
  2447 + $el = isValid ? $(obj).first() : [];
  2448 + return $el.length ? $el : null;
  2449 + }
  2450 + })();
  2451 +});
\ No newline at end of file
... ...
... ... @@ -2,6 +2,7 @@
2 2 //= require kanjai/jquery-ui
3 3 //= require kanjai/admin/popper.js/popper.js
4 4 //= require kanjai/admin/bootstrap/bootstrap
  5 +//= require kanjai/admin/tagsinput/typeahead
5 6 //= require kanjai/rails
6 7
7 8
... ... @@ -12,6 +13,8 @@
12 13 //= require kanjai/lib/epiceditor
13 14 //= require kanjai/lib/fileinput
14 15
  16 +//= require kanjai/admin/jquery.fileupload
  17 +
15 18 //= require kanjai/froala_editor/froala_editor.min
16 19 //= require kanjai/froala_editor/plugins/align.min
17 20 //= require kanjai/froala_editor/plugins/char_counter.min
... ... @@ -37,4 +40,6 @@
37 40 //= require kanjai/froala_editor/plugins/url.min
38 41 //= require kanjai/froala_editor/plugins/video.min
39 42
  43 +
  44 +
40 45 //= require_tree ./admin/.
... ...
1 1 (function($, undefined) {
2 2
3   - /**
4   - * Unobtrusive scripting adapter for jQuery
5   - * https://github.com/rails/jquery-ujs
6   - *
7   - * Requires jQuery 1.8.0 or later.
8   - *
9   - * Released under the MIT license
10   - *
11   - */
12   -
13   - // Cut down on the number of issues from people inadvertently including jquery_ujs twice
14   - // by detecting and raising an error when it happens.
15   - if ( $.rails !== undefined ) {
16   - $.error('jquery-ujs has already been loaded!');
17   - }
  3 +/**
  4 + * Unobtrusive scripting adapter for jQuery
  5 + * https://github.com/rails/jquery-ujs
  6 + *
  7 + * Requires jQuery 1.8.0 or later.
  8 + *
  9 + * Released under the MIT license
  10 + *
  11 + */
  12 +
  13 + // Cut down on the number of issues from people inadvertently including jquery_ujs twice
  14 + // by detecting and raising an error when it happens.
  15 + 'use strict';
  16 +
  17 + if ( $.rails !== undefined ) {
  18 + $.error('jquery-ujs has already been loaded!');
  19 + }
  20 +
  21 + // Shorthand to make it a little easier to call public rails functions from within rails.js
  22 + var rails;
  23 + var $document = $(document);
  24 +
  25 + $.rails = rails = {
  26 + // Link elements bound by jquery-ujs
  27 + linkClickSelector: 'a[data-confirm], a[data-method], a[data-remote]:not([disabled]), a[data-disable-with], a[data-disable]',
  28 +
  29 + // Button elements bound by jquery-ujs
  30 + buttonClickSelector: 'button[data-remote]:not([form]):not(form button), button[data-confirm]:not([form]):not(form button)',
  31 +
  32 + // Select elements bound by jquery-ujs
  33 + inputChangeSelector: 'select[data-remote], input[data-remote], textarea[data-remote]',
  34 +
  35 + // Form elements bound by jquery-ujs
  36 + formSubmitSelector: 'form',
  37 +
  38 + // Form input elements bound by jquery-ujs
  39 + formInputClickSelector: 'form input[type=submit], form input[type=image], form button[type=submit], form button:not([type]), input[type=submit][form], input[type=image][form], button[type=submit][form], button[form]:not([type])',
  40 +
  41 + // Form input elements disabled during form submission
  42 + disableSelector: 'input[data-disable-with]:enabled, button[data-disable-with]:enabled, textarea[data-disable-with]:enabled, input[data-disable]:enabled, button[data-disable]:enabled, textarea[data-disable]:enabled',
  43 +
  44 + // Form input elements re-enabled after form submission
  45 + enableSelector: 'input[data-disable-with]:disabled, button[data-disable-with]:disabled, textarea[data-disable-with]:disabled, input[data-disable]:disabled, button[data-disable]:disabled, textarea[data-disable]:disabled',
  46 +
  47 + // Form required input elements
  48 + requiredInputSelector: 'input[name][required]:not([disabled]), textarea[name][required]:not([disabled])',
  49 +
  50 + // Form file input elements
  51 + fileInputSelector: 'input[name][type=file]:not([disabled])',
  52 +
  53 + // Link onClick disable selector with possible reenable after remote submission
  54 + linkDisableSelector: 'a[data-disable-with], a[data-disable]',
  55 +
  56 + // Button onClick disable selector with possible reenable after remote submission
  57 + buttonDisableSelector: 'button[data-remote][data-disable-with], button[data-remote][data-disable]',
  58 +
  59 + // Up-to-date Cross-Site Request Forgery token
  60 + csrfToken: function() {
  61 + return $('meta[name=csrf-token]').attr('content');
  62 + },
  63 +
  64 + // URL param that must contain the CSRF token
  65 + csrfParam: function() {
  66 + return $('meta[name=csrf-param]').attr('content');
  67 + },
  68 +
  69 + // Make sure that every Ajax request sends the CSRF token
  70 + CSRFProtection: function(xhr) {
  71 + var token = rails.csrfToken();
  72 + if (token) xhr.setRequestHeader('X-CSRF-Token', token);
  73 + },
  74 +
  75 + // Make sure that all forms have actual up-to-date tokens (cached forms contain old ones)
  76 + refreshCSRFTokens: function(){
  77 + $('form input[name="' + rails.csrfParam() + '"]').val(rails.csrfToken());
  78 + },
  79 +
  80 + // Triggers an event on an element and returns false if the event result is false
  81 + fire: function(obj, name, data) {
  82 + var event = $.Event(name);
  83 + obj.trigger(event, data);
  84 + return event.result !== false;
  85 + },
  86 +
  87 + // Default confirm dialog, may be overridden with custom confirm dialog in $.rails.confirm
  88 + confirm: function(message) {
  89 + return confirm(message);
  90 + },
  91 +
  92 + // Default ajax function, may be overridden with custom function in $.rails.ajax
  93 + ajax: function(options) {
  94 + return $.ajax(options);
  95 + },
  96 +
  97 + // Default way to get an element's href. May be overridden at $.rails.href.
  98 + href: function(element) {
  99 + return element[0].href;
  100 + },
  101 +
  102 + // Checks "data-remote" if true to handle the request through a XHR request.
  103 + isRemote: function(element) {
  104 + return element.data('remote') !== undefined && element.data('remote') !== false;
  105 + },
  106 +
  107 + // Submits "remote" forms and links with ajax
  108 + handleRemote: function(element) {
  109 + var method, url, data, withCredentials, dataType, options;
  110 +
  111 + if (rails.fire(element, 'ajax:before')) {
  112 + withCredentials = element.data('with-credentials') || null;
  113 + dataType = element.data('type') || ($.ajaxSettings && $.ajaxSettings.dataType);
  114 +
  115 + if (element.is('form')) {
  116 + method = element.data('ujs:submit-button-formmethod') || element.attr('method');
  117 + url = element.data('ujs:submit-button-formaction') || element.attr('action');
  118 + data = $(element[0]).serializeArray();
  119 + // memoized value from clicked submit button
  120 + var button = element.data('ujs:submit-button');
  121 + if (button) {
  122 + data.push(button);
  123 + element.data('ujs:submit-button', null);
  124 + }
  125 + element.data('ujs:submit-button-formmethod', null);
  126 + element.data('ujs:submit-button-formaction', null);
  127 + } else if (element.is(rails.inputChangeSelector)) {
  128 + method = element.data('method');
  129 + url = element.data('url');
  130 + data = element.serialize();
  131 + if (element.data('params')) data = data + '&' + element.data('params');
  132 + } else if (element.is(rails.buttonClickSelector)) {
  133 + method = element.data('method') || 'get';
  134 + url = element.data('url');
  135 + data = element.serialize();
  136 + if (element.data('params')) data = data + '&' + element.data('params');
  137 + } else {
  138 + method = element.data('method');
  139 + url = rails.href(element);
  140 + data = element.data('params') || null;
  141 + }
18 142
19   - // Shorthand to make it a little easier to call public rails functions from within rails.js
20   - var rails;
21   - var $document = $(document);
22   -
23   - $.rails = rails = {
24   - // Link elements bound by jquery-ujs
25   - linkClickSelector: 'a[data-confirm], a[data-method], a[data-remote], a[data-disable-with], a[data-disable]',
26   -
27   - // Button elements bound by jquery-ujs
28   - buttonClickSelector: 'button[data-remote]:not(form button), button[data-confirm]:not(form button)',
29   -
30   - // Select elements bound by jquery-ujs
31   - inputChangeSelector: 'select[data-remote], input[data-remote], textarea[data-remote]',
32   -
33   - // Form elements bound by jquery-ujs
34   - formSubmitSelector: 'form',
35   -
36   - // Form input elements bound by jquery-ujs
37   - formInputClickSelector: 'form input[type=submit], form input[type=image], form button[type=submit], form button:not([type]), input[type=submit][form], input[type=image][form], button[type=submit][form], button[form]:not([type])',
38   -
39   - // Form input elements disabled during form submission
40   - disableSelector: 'input[data-disable-with]:enabled, button[data-disable-with]:enabled, textarea[data-disable-with]:enabled, input[data-disable]:enabled, button[data-disable]:enabled, textarea[data-disable]:enabled',
41   -
42   - // Form input elements re-enabled after form submission
43   - enableSelector: 'input[data-disable-with]:disabled, button[data-disable-with]:disabled, textarea[data-disable-with]:disabled, input[data-disable]:disabled, button[data-disable]:disabled, textarea[data-disable]:disabled',
44   -
45   - // Form required input elements
46   - requiredInputSelector: 'input[name][required]:not([disabled]),textarea[name][required]:not([disabled])',
47   -
48   - // Form file input elements
49   - fileInputSelector: 'input[type=file]',
50   -
51   - // Link onClick disable selector with possible reenable after remote submission
52   - linkDisableSelector: 'a[data-disable-with], a[data-disable]',
53   -
54   - // Button onClick disable selector with possible reenable after remote submission
55   - buttonDisableSelector: 'button[data-remote][data-disable-with], button[data-remote][data-disable]',
56   -
57   - // Make sure that every Ajax request sends the CSRF token
58   - CSRFProtection: function(xhr) {
59   - var token = $('meta[name="csrf-token"]').attr('content');
60   - if (token) xhr.setRequestHeader('X-CSRF-Token', token);
61   - },
62   -
63   - // making sure that all forms have actual up-to-date token(cached forms contain old one)
64   - refreshCSRFTokens: function(){
65   - var csrfToken = $('meta[name=csrf-token]').attr('content');
66   - var csrfParam = $('meta[name=csrf-param]').attr('content');
67   - $('form input[name="' + csrfParam + '"]').val(csrfToken);
68   - },
69   -
70   - // Triggers an event on an element and returns false if the event result is false
71   - fire: function(obj, name, data) {
72   - var event = $.Event(name);
73   - obj.trigger(event, data);
74   - return event.result !== false;
75   - },
76   -
77   - // Default confirm dialog, may be overridden with custom confirm dialog in $.rails.confirm
78   - confirm: function(message) {
79   - return confirm(message);
80   - },
81   -
82   - // Default ajax function, may be overridden with custom function in $.rails.ajax
83   - ajax: function(options) {
84   - return $.ajax(options);
85   - },
86   -
87   - // Default way to get an element's href. May be overridden at $.rails.href.
88   - href: function(element) {
89   - return element.attr('href');
90   - },
91   -
92   - // Submits "remote" forms and links with ajax
93   - handleRemote: function(element) {
94   - var method, url, data, elCrossDomain, crossDomain, withCredentials, dataType, options;
95   -
96   - if (rails.fire(element, 'ajax:before')) {
97   - elCrossDomain = element.data('cross-domain');
98   - crossDomain = elCrossDomain === undefined ? null : elCrossDomain;
99   - withCredentials = element.data('with-credentials') || null;
100   - dataType = element.data('type') || ($.ajaxSettings && $.ajaxSettings.dataType);
101   -
102   - if (element.is('form')) {
103   - method = element.attr('method');
104   - url = element.attr('action');
105   - data = element.serializeArray();
106   - // memoized value from clicked submit button
107   - var button = element.data('ujs:submit-button');
108   - if (button) {
109   - data.push(button);
110   - element.data('ujs:submit-button', null);
111   - }
112   - } else if (element.is(rails.inputChangeSelector)) {
113   - method = element.data('method');
114   - url = element.data('url');
115   - data = element.serialize();
116   - if (element.data('params')) data = data + "&" + element.data('params');
117   - } else if (element.is(rails.buttonClickSelector)) {
118   - method = element.data('method') || 'get';
119   - url = element.data('url');
120   - data = element.serialize();
121   - if (element.data('params')) data = data + "&" + element.data('params');
122   - } else {
123   - method = element.data('method');
124   - url = rails.href(element);
125   - data = element.data('params') || null;
126   - }
127   -
128   - options = {
129   - type: method || 'GET', data: data, dataType: dataType,
130   - // stopping the "ajax:beforeSend" event will cancel the ajax request
131   - beforeSend: function(xhr, settings) {
132   - if (settings.dataType === undefined) {
133   - xhr.setRequestHeader('accept', '*/*;q=0.5, ' + settings.accepts.script);
134   - }
135   - if (rails.fire(element, 'ajax:beforeSend', [xhr, settings])) {
136   - element.trigger('ajax:send', xhr);
137   - } else {
138   - return false;
139   - }
140   - },
141   - success: function(data, status, xhr) {
142   - element.trigger('ajax:success', [data, status, xhr]);
143   - },
144   - complete: function(xhr, status) {
145   - element.trigger('ajax:complete', [xhr, status]);
146   - },
147   - error: function(xhr, status, error) {
148   - element.trigger('ajax:error', [xhr, status, error]);
149   - },
150   - crossDomain: crossDomain
151   - };
152   -
153   - // There is no withCredentials for IE6-8 when
154   - // "Enable native XMLHTTP support" is disabled
155   - if (withCredentials) {
156   - options.xhrFields = {
157   - withCredentials: withCredentials
158   - };
159   - }
160   -
161   - // Only pass url to `ajax` options if not blank
162   - if (url) { options.url = url; }
163   -
164   - return rails.ajax(options);
165   - } else {
166   - return false;
  143 + options = {
  144 + type: method || 'GET', data: data, dataType: dataType,
  145 + // stopping the "ajax:beforeSend" event will cancel the ajax request
  146 + beforeSend: function(xhr, settings) {
  147 + if (settings.dataType === undefined) {
  148 + xhr.setRequestHeader('accept', '*/*;q=0.5, ' + settings.accepts.script);
167 149 }
168   - },
169   -
170   - // Handles "data-method" on links such as:
171   - // <a href="/users/5" data-method="delete" rel="nofollow" data-confirm="Are you sure?">Delete</a>
172   - handleMethod: function(link) {
173   - var href = rails.href(link),
174   - method = link.data('method'),
175   - target = link.attr('target'),
176   - csrfToken = $('meta[name=csrf-token]').attr('content'),
177   - csrfParam = $('meta[name=csrf-param]').attr('content'),
178   - form = $('<form method="post" action="' + href + '"></form>'),
179   - metadataInput = '<input name="_method" value="' + method + '" type="hidden" />';
180   -
181   - if (csrfParam !== undefined && csrfToken !== undefined) {
182   - metadataInput += '<input name="' + csrfParam + '" value="' + csrfToken + '" type="hidden" />';
  150 + if (rails.fire(element, 'ajax:beforeSend', [xhr, settings])) {
  151 + element.trigger('ajax:send', xhr);
  152 + } else {
  153 + return false;
183 154 }
  155 + },
  156 + success: function(data, status, xhr) {
  157 + element.trigger('ajax:success', [data, status, xhr]);
  158 + },
  159 + complete: function(xhr, status) {
  160 + element.trigger('ajax:complete', [xhr, status]);
  161 + },
  162 + error: function(xhr, status, error) {
  163 + element.trigger('ajax:error', [xhr, status, error]);
  164 + },
  165 + crossDomain: rails.isCrossDomain(url)
  166 + };
  167 +
  168 + // There is no withCredentials for IE6-8 when
  169 + // "Enable native XMLHTTP support" is disabled
  170 + if (withCredentials) {
  171 + options.xhrFields = {
  172 + withCredentials: withCredentials
  173 + };
  174 + }
184 175
185   - if (target) { form.attr('target', target); }
186   -
187   - form.hide().append(metadataInput).appendTo('body');
188   - form.submit();
189   - },
190   -
191   - // Helper function that returns form elements that match the specified CSS selector
192   - // If form is actually a "form" element this will return associated elements outside the from that have
193   - // the html form attribute set
194   - formElements: function(form, selector) {
195   - return form.is('form') ? $(form[0].elements).filter(selector) : form.find(selector);
196   - },
197   -
198   - /* Disables form elements:
199   - - Caches element value in 'ujs:enable-with' data store
200   - - Replaces element text with value of 'data-disable-with' attribute
201   - - Sets disabled property to true
202   - */
203   - disableFormElements: function(form) {
204   - rails.formElements(form, rails.disableSelector).each(function() {
205   - rails.disableFormElement($(this));
206   - });
207   - },
208   -
209   - disableFormElement: function(element) {
210   - var method, replacement;
211   -
212   - method = element.is('button') ? 'html' : 'val';
213   - replacement = element.data('disable-with');
214   -
215   - element.data('ujs:enable-with', element[method]());
216   - if (replacement !== undefined) {
217   - element[method](replacement);
  176 + // Only pass url to `ajax` options if not blank
  177 + if (url) { options.url = url; }
  178 +
  179 + return rails.ajax(options);
  180 + } else {
  181 + return false;
  182 + }
  183 + },
  184 +
  185 + // Determines if the request is a cross domain request.
  186 + isCrossDomain: function(url) {
  187 + var originAnchor = document.createElement('a');
  188 + originAnchor.href = location.href;
  189 + var urlAnchor = document.createElement('a');
  190 +
  191 + try {
  192 + urlAnchor.href = url;
  193 + // This is a workaround to a IE bug.
  194 + urlAnchor.href = urlAnchor.href;
  195 +
  196 + // If URL protocol is false or is a string containing a single colon
  197 + // *and* host are false, assume it is not a cross-domain request
  198 + // (should only be the case for IE7 and IE compatibility mode).
  199 + // Otherwise, evaluate protocol and host of the URL against the origin
  200 + // protocol and host.
  201 + return !(((!urlAnchor.protocol || urlAnchor.protocol === ':') && !urlAnchor.host) ||
  202 + (originAnchor.protocol + '//' + originAnchor.host ===
  203 + urlAnchor.protocol + '//' + urlAnchor.host));
  204 + } catch (e) {
  205 + // If there is an error parsing the URL, assume it is crossDomain.
  206 + return true;
  207 + }
  208 + },
  209 +
  210 + // Handles "data-method" on links such as:
  211 + // <a href="/users/5" data-method="delete" rel="nofollow" data-confirm="Are you sure?">Delete</a>
  212 + handleMethod: function(link) {
  213 + var href = rails.href(link),
  214 + method = link.data('method'),
  215 + target = link.attr('target'),
  216 + csrfToken = rails.csrfToken(),
  217 + csrfParam = rails.csrfParam(),
  218 + form = $('<form method="post" action="' + href + '"></form>'),
  219 + metadataInput = '<input name="_method" value="' + method + '" type="hidden" />';
  220 +
  221 + if (csrfParam !== undefined && csrfToken !== undefined && !rails.isCrossDomain(href)) {
  222 + metadataInput += '<input name="' + csrfParam + '" value="' + csrfToken + '" type="hidden" />';
  223 + }
  224 +
  225 + if (target) { form.attr('target', target); }
  226 +
  227 + form.hide().append(metadataInput).appendTo('body');
  228 + form.submit();
  229 + },
  230 +
  231 + // Helper function that returns form elements that match the specified CSS selector
  232 + // If form is actually a "form" element this will return associated elements outside the from that have
  233 + // the html form attribute set
  234 + formElements: function(form, selector) {
  235 + return form.is('form') ? $(form[0].elements).filter(selector) : form.find(selector);
  236 + },
  237 +
  238 + /* Disables form elements:
  239 + - Caches element value in 'ujs:enable-with' data store
  240 + - Replaces element text with value of 'data-disable-with' attribute
  241 + - Sets disabled property to true
  242 + */
  243 + disableFormElements: function(form) {
  244 + rails.formElements(form, rails.disableSelector).each(function() {
  245 + rails.disableFormElement($(this));
  246 + });
  247 + },
  248 +
  249 + disableFormElement: function(element) {
  250 + var method, replacement;
  251 +
  252 + method = element.is('button') ? 'html' : 'val';
  253 + replacement = element.data('disable-with');
  254 +
  255 + if (replacement !== undefined) {
  256 + element.data('ujs:enable-with', element[method]());
  257 + element[method](replacement);
  258 + }
  259 +
  260 + element.prop('disabled', true);
  261 + element.data('ujs:disabled', true);
  262 + },
  263 +
  264 + /* Re-enables disabled form elements:
  265 + - Replaces element text with cached value from 'ujs:enable-with' data store (created in `disableFormElements`)
  266 + - Sets disabled property to false
  267 + */
  268 + enableFormElements: function(form) {
  269 + rails.formElements(form, rails.enableSelector).each(function() {
  270 + rails.enableFormElement($(this));
  271 + });
  272 + },
  273 +
  274 + enableFormElement: function(element) {
  275 + var method = element.is('button') ? 'html' : 'val';
  276 + if (element.data('ujs:enable-with') !== undefined) {
  277 + element[method](element.data('ujs:enable-with'));
  278 + element.removeData('ujs:enable-with'); // clean up cache
  279 + }
  280 + element.prop('disabled', false);
  281 + element.removeData('ujs:disabled');
  282 + },
  283 +
  284 + /* For 'data-confirm' attribute:
  285 + - Fires `confirm` event
  286 + - Shows the confirmation dialog
  287 + - Fires the `confirm:complete` event
  288 +
  289 + Returns `true` if no function stops the chain and user chose yes; `false` otherwise.
  290 + Attaching a handler to the element's `confirm` event that returns a `falsy` value cancels the confirmation dialog.
  291 + Attaching a handler to the element's `confirm:complete` event that returns a `falsy` value makes this function
  292 + return false. The `confirm:complete` event is fired whether or not the user answered true or false to the dialog.
  293 + */
  294 + allowAction: function(element) {
  295 + var message = element.data('confirm'),
  296 + answer = false, callback;
  297 + if (!message) { return true; }
  298 +
  299 + if (rails.fire(element, 'confirm')) {
  300 + try {
  301 + answer = rails.confirm(message);
  302 + } catch (e) {
  303 + (console.error || console.log).call(console, e.stack || e);
  304 + }
  305 + callback = rails.fire(element, 'confirm:complete', [answer]);
  306 + }
  307 + return answer && callback;
  308 + },
  309 +
  310 + // Helper function which checks for blank inputs in a form that match the specified CSS selector
  311 + blankInputs: function(form, specifiedSelector, nonBlank) {
  312 + var foundInputs = $(),
  313 + input,
  314 + valueToCheck,
  315 + radiosForNameWithNoneSelected,
  316 + radioName,
  317 + selector = specifiedSelector || 'input,textarea',
  318 + requiredInputs = form.find(selector),
  319 + checkedRadioButtonNames = {};
  320 +
  321 + requiredInputs.each(function() {
  322 + input = $(this);
  323 + if (input.is('input[type=radio]')) {
  324 +
  325 + // Don't count unchecked required radio as blank if other radio with same name is checked,
  326 + // regardless of whether same-name radio input has required attribute or not. The spec
  327 + // states https://www.w3.org/TR/html5/forms.html#the-required-attribute
  328 + radioName = input.attr('name');
  329 +
  330 + // Skip if we've already seen the radio with this name.
  331 + if (!checkedRadioButtonNames[radioName]) {
  332 +
  333 + // If none checked
  334 + if (form.find('input[type=radio]:checked[name="' + radioName + '"]').length === 0) {
  335 + radiosForNameWithNoneSelected = form.find(
  336 + 'input[type=radio][name="' + radioName + '"]');
  337 + foundInputs = foundInputs.add(radiosForNameWithNoneSelected);
218 338 }
219 339
220   - element.prop('disabled', true);
221   - },
222   -
223   - /* Re-enables disabled form elements:
224   - - Replaces element text with cached value from 'ujs:enable-with' data store (created in `disableFormElements`)
225   - - Sets disabled property to false
226   - */
227   - enableFormElements: function(form) {
228   - rails.formElements(form, rails.enableSelector).each(function() {
229   - rails.enableFormElement($(this));
230   - });
231   - },
232   -
233   - enableFormElement: function(element) {
234   - var method = element.is('button') ? 'html' : 'val';
235   - if (element.data('ujs:enable-with')) element[method](element.data('ujs:enable-with'));
236   - element.prop('disabled', false);
237   - },
238   -
239   - /* For 'data-confirm' attribute:
240   - - Fires `confirm` event
241   - - Shows the confirmation dialog
242   - - Fires the `confirm:complete` event
243   -
244   - Returns `true` if no function stops the chain and user chose yes; `false` otherwise.
245   - Attaching a handler to the element's `confirm` event that returns a `falsy` value cancels the confirmation dialog.
246   - Attaching a handler to the element's `confirm:complete` event that returns a `falsy` value makes this function
247   - return false. The `confirm:complete` event is fired whether or not the user answered true or false to the dialog.
248   - */
249   - allowAction: function(element) {
250   - var message = element.data('confirm'),
251   - answer = false, callback;
252   - if (!message) { return true; }
253   -
254   - if (rails.fire(element, 'confirm')) {
255   - answer = rails.confirm(message);
256   - callback = rails.fire(element, 'confirm:complete', [answer]);
257   - }
258   - return answer && callback;
259   - },
260   -
261   - // Helper function which checks for blank inputs in a form that match the specified CSS selector
262   - blankInputs: function(form, specifiedSelector, nonBlank) {
263   - var inputs = $(), input, valueToCheck,
264   - selector = specifiedSelector || 'input,textarea',
265   - allInputs = form.find(selector);
266   -
267   - allInputs.each(function() {
268   - input = $(this);
269   - valueToCheck = input.is('input[type=checkbox],input[type=radio]') ? input.is(':checked') : input.val();
270   - // If nonBlank and valueToCheck are both truthy, or nonBlank and valueToCheck are both falsey
271   - if (!valueToCheck === !nonBlank) {
272   -
273   - // Don't count unchecked required radio if other radio with same name is checked
274   - if (input.is('input[type=radio]') && allInputs.filter('input[type=radio]:checked[name="' + input.attr('name') + '"]').length) {
275   - return true; // Skip to next input
276   - }
277   -
278   - inputs = inputs.add(input);
279   - }
280   - });
281   - return inputs.length ? inputs : false;
282   - },
283   -
284   - // Helper function which checks for non-blank inputs in a form that match the specified CSS selector
285   - nonBlankInputs: function(form, specifiedSelector) {
286   - return rails.blankInputs(form, specifiedSelector, true); // true specifies nonBlank
287   - },
288   -
289   - // Helper function, needed to provide consistent behavior in IE
290   - stopEverything: function(e) {
291   - $(e.target).trigger('ujs:everythingStopped');
292   - e.stopImmediatePropagation();
293   - return false;
294   - },
295   -
296   - // replace element's html with the 'data-disable-with' after storing original html
297   - // and prevent clicking on it
298   - disableElement: function(element) {
299   - var replacement = element.data('disable-with');
300   -
301   - element.data('ujs:enable-with', element.html()); // store enabled state
302   - if (replacement !== undefined) {
303   - element.html(replacement);
304   - }
  340 + // We only need to check each name once.
  341 + checkedRadioButtonNames[radioName] = radioName;
  342 + }
  343 + } else {
  344 + valueToCheck = input.is('input[type=checkbox],input[type=radio]') ? input.is(':checked') : !!input.val();
  345 + if (valueToCheck === nonBlank) {
  346 + foundInputs = foundInputs.add(input);
  347 + }
  348 + }
  349 + });
  350 + return foundInputs.length ? foundInputs : false;
  351 + },
  352 +
  353 + // Helper function which checks for non-blank inputs in a form that match the specified CSS selector
  354 + nonBlankInputs: function(form, specifiedSelector) {
  355 + return rails.blankInputs(form, specifiedSelector, true); // true specifies nonBlank
  356 + },
  357 +
  358 + // Helper function, needed to provide consistent behavior in IE
  359 + stopEverything: function(e) {
  360 + $(e.target).trigger('ujs:everythingStopped');
  361 + e.stopImmediatePropagation();
  362 + return false;
  363 + },
  364 +
  365 + // Replace element's html with the 'data-disable-with' after storing original html
  366 + // and prevent clicking on it
  367 + disableElement: function(element) {
  368 + var replacement = element.data('disable-with');
  369 +
  370 + if (replacement !== undefined) {
  371 + element.data('ujs:enable-with', element.html()); // store enabled state
  372 + element.html(replacement);
  373 + }
  374 +
  375 + element.bind('click.railsDisable', function(e) { // prevent further clicking
  376 + return rails.stopEverything(e);
  377 + });
  378 + element.data('ujs:disabled', true);
  379 + },
  380 +
  381 + // Restore element to its original state which was disabled by 'disableElement' above
  382 + enableElement: function(element) {
  383 + if (element.data('ujs:enable-with') !== undefined) {
  384 + element.html(element.data('ujs:enable-with')); // set to old enabled state
  385 + element.removeData('ujs:enable-with'); // clean up cache
  386 + }
  387 + element.unbind('click.railsDisable'); // enable element
  388 + element.removeData('ujs:disabled');
  389 + }
  390 + };
305 391
306   - element.bind('click.railsDisable', function(e) { // prevent further clicking
307   - return rails.stopEverything(e);
308   - });
309   - },
  392 + if (rails.fire($document, 'rails:attachBindings')) {
310 393
311   - // restore element to its original state which was disabled by 'disableElement' above
312   - enableElement: function(element) {
313   - if (element.data('ujs:enable-with') !== undefined) {
314   - element.html(element.data('ujs:enable-with')); // set to old enabled state
315   - element.removeData('ujs:enable-with'); // clean up cache
316   - }
317   - element.unbind('click.railsDisable'); // enable element
  394 + $.ajaxPrefilter(function(options, originalOptions, xhr){ if ( !options.crossDomain ) { rails.CSRFProtection(xhr); }});
  395 +
  396 + // This event works the same as the load event, except that it fires every
  397 + // time the page is loaded.
  398 + //
  399 + // See https://github.com/rails/jquery-ujs/issues/357
  400 + // See https://developer.mozilla.org/en-US/docs/Using_Firefox_1.5_caching
  401 + $(window).on('pageshow.rails', function () {
  402 + $($.rails.enableSelector).each(function () {
  403 + var element = $(this);
  404 +
  405 + if (element.data('ujs:disabled')) {
  406 + $.rails.enableFormElement(element);
318 407 }
319   - };
320   -
321   - if (rails.fire($document, 'rails:attachBindings')) {
322   -
323   - $.ajaxPrefilter(function(options, originalOptions, xhr){ if ( !options.crossDomain ) { rails.CSRFProtection(xhr); }});
324   -
325   - // This event works the same as the load event, except that it fires every
326   - // time the page is loaded.
327   - //
328   - // See https://github.com/rails/jquery-ujs/issues/357
329   - // See https://developer.mozilla.org/en-US/docs/Using_Firefox_1.5_caching
330   - $(window).on("pageshow.rails", function () {
331   - $($.rails.enableSelector).each(function () {
332   - var element = $(this);
333   -
334   - if (element.data("ujs:enable-with")) {
335   - $.rails.enableFormElement(element);
336   - }
337   - });
338   -
339   - $($.rails.linkDisableSelector).each(function () {
340   - var element = $(this);
341   -
342   - if (element.data("ujs:enable-with")) {
343   - $.rails.enableElement(element);
344   - }
345   - });
346   - });
347   -
348   - $document.delegate(rails.linkDisableSelector, 'ajax:complete', function() {
349   - rails.enableElement($(this));
350   - });
351   -
352   - $document.delegate(rails.buttonDisableSelector, 'ajax:complete', function() {
353   - rails.enableFormElement($(this));
354   - });
355   -
356   - $document.delegate(rails.linkClickSelector, 'click.rails', function(e) {
357   - var link = $(this), method = link.data('method'), data = link.data('params'), metaClick = e.metaKey || e.ctrlKey;
358   - if (!rails.allowAction(link)) return rails.stopEverything(e);
359   -
360   - if (!metaClick && link.is(rails.linkDisableSelector)) rails.disableElement(link);
361   -
362   - if (link.data('remote') !== undefined) {
363   - if (metaClick && (!method || method === 'GET') && !data) { return true; }
364   -
365   - var handleRemote = rails.handleRemote(link);
366   - // response from rails.handleRemote() will either be false or a deferred object promise.
367   - if (handleRemote === false) {
368   - rails.enableElement(link);
369   - } else {
370   - handleRemote.error( function() { rails.enableElement(link); } );
371   - }
372   - return false;
373   -
374   - } else if (link.data('method')) {
375   - rails.handleMethod(link);
376   - return false;
377   - }
378   - });
  408 + });
379 409
380   - $document.delegate(rails.buttonClickSelector, 'click.rails', function(e) {
381   - var button = $(this);
  410 + $($.rails.linkDisableSelector).each(function () {
  411 + var element = $(this);
382 412
383   - if (!rails.allowAction(button)) return rails.stopEverything(e);
  413 + if (element.data('ujs:disabled')) {
  414 + $.rails.enableElement(element);
  415 + }
  416 + });
  417 + });
384 418
385   - if (button.is(rails.buttonDisableSelector)) rails.disableFormElement(button);
  419 + $document.on('ajax:complete', rails.linkDisableSelector, function() {
  420 + rails.enableElement($(this));
  421 + });
386 422
387   - var handleRemote = rails.handleRemote(button);
388   - // response from rails.handleRemote() will either be false or a deferred object promise.
389   - if (handleRemote === false) {
390   - rails.enableFormElement(button);
391   - } else {
392   - handleRemote.error( function() { rails.enableFormElement(button); } );
393   - }
394   - return false;
395   - });
396   -
397   - $document.delegate(rails.inputChangeSelector, 'change.rails', function(e) {
398   - var link = $(this);
399   - if (!rails.allowAction(link)) return rails.stopEverything(e);
400   -
401   - rails.handleRemote(link);
402   - return false;
403   - });
404   -
405   - $document.delegate(rails.formSubmitSelector, 'submit.rails', function(e) {
406   - var form = $(this),
407   - remote = form.data('remote') !== undefined,
408   - blankRequiredInputs,
409   - nonBlankFileInputs;
410   -
411   - if (!rails.allowAction(form)) return rails.stopEverything(e);
412   -
413   - // skip other logic when required values are missing or file upload is present
414   - if (form.attr('novalidate') == undefined) {
415   - blankRequiredInputs = rails.blankInputs(form, rails.requiredInputSelector);
416   - if (blankRequiredInputs && rails.fire(form, 'ajax:aborted:required', [blankRequiredInputs])) {
417   - return rails.stopEverything(e);
418   - }
419   - }
  423 + $document.on('ajax:complete', rails.buttonDisableSelector, function() {
  424 + rails.enableFormElement($(this));
  425 + });
420 426
421   - if (remote) {
422   - nonBlankFileInputs = rails.nonBlankInputs(form, rails.fileInputSelector);
423   - if (nonBlankFileInputs) {
424   - // slight timeout so that the submit button gets properly serialized
425   - // (make it easy for event handler to serialize form without disabled values)
426   - setTimeout(function(){ rails.disableFormElements(form); }, 13);
427   - var aborted = rails.fire(form, 'ajax:aborted:file', [nonBlankFileInputs]);
  427 + $document.on('click.rails', rails.linkClickSelector, function(e) {
  428 + var link = $(this), method = link.data('method'), data = link.data('params'), metaClick = e.metaKey || e.ctrlKey;
  429 + if (!rails.allowAction(link)) return rails.stopEverything(e);
428 430
429   - // re-enable form elements if event bindings return false (canceling normal form submission)
430   - if (!aborted) { setTimeout(function(){ rails.enableFormElements(form); }, 13); }
  431 + if (!metaClick && link.is(rails.linkDisableSelector)) rails.disableElement(link);
431 432
432   - return aborted;
433   - }
  433 + if (rails.isRemote(link)) {
  434 + if (metaClick && (!method || method === 'GET') && !data) { return true; }
434 435
435   - rails.handleRemote(form);
436   - return false;
  436 + var handleRemote = rails.handleRemote(link);
  437 + // Response from rails.handleRemote() will either be false or a deferred object promise.
  438 + if (handleRemote === false) {
  439 + rails.enableElement(link);
  440 + } else {
  441 + handleRemote.fail( function() { rails.enableElement(link); } );
  442 + }
  443 + return false;
  444 +
  445 + } else if (method) {
  446 + rails.handleMethod(link);
  447 + return false;
  448 + }
  449 + });
  450 +
  451 + $document.on('click.rails', rails.buttonClickSelector, function(e) {
  452 + var button = $(this);
  453 +
  454 + if (!rails.allowAction(button) || !rails.isRemote(button)) return rails.stopEverything(e);
  455 +
  456 + if (button.is(rails.buttonDisableSelector)) rails.disableFormElement(button);
  457 +
  458 + var handleRemote = rails.handleRemote(button);
  459 + // Response from rails.handleRemote() will either be false or a deferred object promise.
  460 + if (handleRemote === false) {
  461 + rails.enableFormElement(button);
  462 + } else {
  463 + handleRemote.fail( function() { rails.enableFormElement(button); } );
  464 + }
  465 + return false;
  466 + });
  467 +
  468 + $document.on('change.rails', rails.inputChangeSelector, function(e) {
  469 + var link = $(this);
  470 + if (!rails.allowAction(link) || !rails.isRemote(link)) return rails.stopEverything(e);
  471 +
  472 + rails.handleRemote(link);
  473 + return false;
  474 + });
  475 +
  476 + $document.on('submit.rails', rails.formSubmitSelector, function(e) {
  477 + var form = $(this),
  478 + remote = rails.isRemote(form),
  479 + blankRequiredInputs,
  480 + nonBlankFileInputs;
  481 +
  482 + if (!rails.allowAction(form)) return rails.stopEverything(e);
  483 +
  484 + // Skip other logic when required values are missing or file upload is present
  485 + if (form.attr('novalidate') === undefined) {
  486 + if (form.data('ujs:formnovalidate-button') === undefined) {
  487 + blankRequiredInputs = rails.blankInputs(form, rails.requiredInputSelector, false);
  488 + if (blankRequiredInputs && rails.fire(form, 'ajax:aborted:required', [blankRequiredInputs])) {
  489 + return rails.stopEverything(e);
  490 + }
  491 + } else {
  492 + // Clear the formnovalidate in case the next button click is not on a formnovalidate button
  493 + // Not strictly necessary to do here, since it is also reset on each button click, but just to be certain
  494 + form.data('ujs:formnovalidate-button', undefined);
  495 + }
  496 + }
437 497
438   - } else {
439   - // slight timeout so that the submit button gets properly serialized
440   - setTimeout(function(){ rails.disableFormElements(form); }, 13);
441   - }
442   - });
  498 + if (remote) {
  499 + nonBlankFileInputs = rails.nonBlankInputs(form, rails.fileInputSelector);
  500 + if (nonBlankFileInputs) {
  501 + // Slight timeout so that the submit button gets properly serialized
  502 + // (make it easy for event handler to serialize form without disabled values)
  503 + setTimeout(function(){ rails.disableFormElements(form); }, 13);
  504 + var aborted = rails.fire(form, 'ajax:aborted:file', [nonBlankFileInputs]);
443 505
444   - $document.delegate(rails.formInputClickSelector, 'click.rails', function(event) {
445   - var button = $(this);
  506 + // Re-enable form elements if event bindings return false (canceling normal form submission)
  507 + if (!aborted) { setTimeout(function(){ rails.enableFormElements(form); }, 13); }
446 508
447   - if (!rails.allowAction(button)) return rails.stopEverything(event);
  509 + return aborted;
  510 + }
448 511
449   - // register the pressed submit button
450   - var name = button.attr('name'),
451   - data = name ? {name:name, value:button.val()} : null;
  512 + rails.handleRemote(form);
  513 + return false;
452 514
453   - button.closest('form').data('ujs:submit-button', data);
454   - });
  515 + } else {
  516 + // Slight timeout so that the submit button gets properly serialized
  517 + setTimeout(function(){ rails.disableFormElements(form); }, 13);
  518 + }
  519 + });
455 520
456   - $document.delegate(rails.formSubmitSelector, 'ajax:send.rails', function(event) {
457   - if (this == event.target) rails.disableFormElements($(this));
458   - });
  521 + $document.on('click.rails', rails.formInputClickSelector, function(event) {
  522 + var button = $(this);
459 523
460   - $document.delegate(rails.formSubmitSelector, 'ajax:complete.rails', function(event) {
461   - if (this == event.target) rails.enableFormElements($(this));
462   - });
  524 + if (!rails.allowAction(button)) return rails.stopEverything(event);
463 525
464   - $(function(){
465   - rails.refreshCSRFTokens();
466   - });
467   - }
  526 + // Register the pressed submit button
  527 + var name = button.attr('name'),
  528 + data = name ? {name:name, value:button.val()} : null;
  529 +
  530 + var form = button.closest('form');
  531 + if (form.length === 0) {
  532 + form = $('#' + button.attr('form'));
  533 + }
  534 + form.data('ujs:submit-button', data);
  535 +
  536 + // Save attributes from button
  537 + form.data('ujs:formnovalidate-button', button.attr('formnovalidate'));
  538 + form.data('ujs:submit-button-formaction', button.attr('formaction'));
  539 + form.data('ujs:submit-button-formmethod', button.attr('formmethod'));
  540 + });
  541 +
  542 + $document.on('ajax:send.rails', rails.formSubmitSelector, function(event) {
  543 + if (this === event.target) rails.disableFormElements($(this));
  544 + });
  545 +
  546 + $document.on('ajax:complete.rails', rails.formSubmitSelector, function(event) {
  547 + if (this === event.target) rails.enableFormElements($(this));
  548 + });
  549 +
  550 + $(function(){
  551 + rails.refreshCSRFTokens();
  552 + });
  553 + }
468 554
469   -})( jQuery );
  555 +})( jQuery );
\ No newline at end of file
... ...
... ... @@ -5238,14 +5238,11 @@ body .jvectormap-zoomout {
5238 5238 /* HTML GENERATOR END */
5239 5239
5240 5240 #gallery_form .file-preview {
5241   - display: inline-block;
5242 5241 width: auto;
5243 5242 }
5244 5243
5245 5244 #gallery_form .file-input{
5246 5245 display: inline-block;
5247   - float: left;
5248   - margin:20px;
5249 5246 }
5250 5247
5251 5248 #gallery_form .file-caption-main{
... ... @@ -5265,6 +5262,12 @@ body .jvectormap-zoomout {
5265 5262 margin: 0 auto;
5266 5263 }
5267 5264
  5265 +#gallery_form{
  5266 + .new-image-wrapper{
  5267 + .close.fileinput-remove{display:none;}
  5268 + }
  5269 +}
  5270 +
5268 5271 /* EMPTY BLOCK */
5269 5272 .empty-block{
5270 5273 text-align: center;
... ... @@ -5275,4 +5278,61 @@ body .jvectormap-zoomout {
5275 5278 font-weight:bold;
5276 5279 }
5277 5280
5278   -.mt-20{margin-top:20px;}
\ No newline at end of file
  5281 +.mt-20{margin-top:20px;}
  5282 +
  5283 +.dropleft.without-icon .dropdown-toggle::before{
  5284 + display:none;
  5285 +}
  5286 +
  5287 +.card-body{
  5288 + position:relative;
  5289 + .content{
  5290 + min-height:50px;
  5291 + margin-right:50px;
  5292 + }
  5293 + .action{
  5294 + position:absolute;
  5295 + right:10px;
  5296 + top:30px;
  5297 + }
  5298 +}
  5299 +
  5300 +.tt-menu {
  5301 + position: absolute;
  5302 + top: 100%;
  5303 + left: 0;
  5304 + z-index: 1000;
  5305 + display: none;
  5306 + float: left;
  5307 + min-width: 160px;
  5308 + padding: 5px 0;
  5309 + margin: 2px 0 0;
  5310 + list-style: none;
  5311 + font-size: 14px;
  5312 + background-color: #ffffff;
  5313 + border: 1px solid #cccccc;
  5314 + border: 1px solid rgba(0, 0, 0, 0.15);
  5315 + border-radius: 4px;
  5316 + -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
  5317 + box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
  5318 + background-clip: padding-box;
  5319 + cursor: pointer;
  5320 +}
  5321 +
  5322 +.tt-suggestion {
  5323 + display: block;
  5324 + padding: 3px 20px;
  5325 + clear: both;
  5326 + font-weight: normal;
  5327 + line-height: 1.428571429;
  5328 + color: #333333;
  5329 + white-space: nowrap;
  5330 +}
  5331 +
  5332 +.tt-suggestion:hover,
  5333 +.tt-suggestion:focus {
  5334 + color: #ffffff;
  5335 + text-decoration: none;
  5336 + outline: 0;
  5337 + background-color: #428bca;
  5338 +}
\ No newline at end of file
... ...
  1 +/**
  2 + *
  3 + * All animations must live in their own file
  4 + * in the animations directory and be included
  5 + * here.
  6 + *
  7 + */
  8 +/**
  9 + * Styles shared by multiple animations
  10 + */
  11 +/**
  12 + * Dots
  13 + */
  14 +@-webkit-keyframes scale {
  15 + 0% {
  16 + -webkit-transform: scale(1);
  17 + transform: scale(1);
  18 + opacity: 1; }
  19 + 45% {
  20 + -webkit-transform: scale(0.1);
  21 + transform: scale(0.1);
  22 + opacity: 0.7; }
  23 + 80% {
  24 + -webkit-transform: scale(1);
  25 + transform: scale(1);
  26 + opacity: 1; } }
  27 +@keyframes scale {
  28 + 0% {
  29 + -webkit-transform: scale(1);
  30 + transform: scale(1);
  31 + opacity: 1; }
  32 + 45% {
  33 + -webkit-transform: scale(0.1);
  34 + transform: scale(0.1);
  35 + opacity: 0.7; }
  36 + 80% {
  37 + -webkit-transform: scale(1);
  38 + transform: scale(1);
  39 + opacity: 1; } }
  40 +
  41 +.ball-pulse > div:nth-child(0) {
  42 + -webkit-animation: scale 0.75s -0.36s infinite cubic-bezier(0.2, 0.68, 0.18, 1.08);
  43 + animation: scale 0.75s -0.36s infinite cubic-bezier(0.2, 0.68, 0.18, 1.08); }
  44 +
  45 +.ball-pulse > div:nth-child(1) {
  46 + -webkit-animation: scale 0.75s -0.24s infinite cubic-bezier(0.2, 0.68, 0.18, 1.08);
  47 + animation: scale 0.75s -0.24s infinite cubic-bezier(0.2, 0.68, 0.18, 1.08); }
  48 +
  49 +.ball-pulse > div:nth-child(2) {
  50 + -webkit-animation: scale 0.75s -0.12s infinite cubic-bezier(0.2, 0.68, 0.18, 1.08);
  51 + animation: scale 0.75s -0.12s infinite cubic-bezier(0.2, 0.68, 0.18, 1.08); }
  52 +
  53 +.ball-pulse > div:nth-child(3) {
  54 + -webkit-animation: scale 0.75s 0s infinite cubic-bezier(0.2, 0.68, 0.18, 1.08);
  55 + animation: scale 0.75s 0s infinite cubic-bezier(0.2, 0.68, 0.18, 1.08); }
  56 +
  57 +.ball-pulse > div {
  58 + background-color: #fff;
  59 + width: 15px;
  60 + height: 15px;
  61 + border-radius: 100%;
  62 + margin: 2px;
  63 + -webkit-animation-fill-mode: both;
  64 + animation-fill-mode: both;
  65 + display: inline-block; }
  66 +
  67 +@-webkit-keyframes ball-pulse-sync {
  68 + 33% {
  69 + -webkit-transform: translateY(10px);
  70 + transform: translateY(10px); }
  71 + 66% {
  72 + -webkit-transform: translateY(-10px);
  73 + transform: translateY(-10px); }
  74 + 100% {
  75 + -webkit-transform: translateY(0);
  76 + transform: translateY(0); } }
  77 +
  78 +@keyframes ball-pulse-sync {
  79 + 33% {
  80 + -webkit-transform: translateY(10px);
  81 + transform: translateY(10px); }
  82 + 66% {
  83 + -webkit-transform: translateY(-10px);
  84 + transform: translateY(-10px); }
  85 + 100% {
  86 + -webkit-transform: translateY(0);
  87 + transform: translateY(0); } }
  88 +
  89 +.ball-pulse-sync > div:nth-child(0) {
  90 + -webkit-animation: ball-pulse-sync 0.6s -0.21s infinite ease-in-out;
  91 + animation: ball-pulse-sync 0.6s -0.21s infinite ease-in-out; }
  92 +
  93 +.ball-pulse-sync > div:nth-child(1) {
  94 + -webkit-animation: ball-pulse-sync 0.6s -0.14s infinite ease-in-out;
  95 + animation: ball-pulse-sync 0.6s -0.14s infinite ease-in-out; }
  96 +
  97 +.ball-pulse-sync > div:nth-child(2) {
  98 + -webkit-animation: ball-pulse-sync 0.6s -0.07s infinite ease-in-out;
  99 + animation: ball-pulse-sync 0.6s -0.07s infinite ease-in-out; }
  100 +
  101 +.ball-pulse-sync > div:nth-child(3) {
  102 + -webkit-animation: ball-pulse-sync 0.6s 0s infinite ease-in-out;
  103 + animation: ball-pulse-sync 0.6s 0s infinite ease-in-out; }
  104 +
  105 +.ball-pulse-sync > div {
  106 + background-color: #fff;
  107 + width: 15px;
  108 + height: 15px;
  109 + border-radius: 100%;
  110 + margin: 2px;
  111 + -webkit-animation-fill-mode: both;
  112 + animation-fill-mode: both;
  113 + display: inline-block; }
  114 +
  115 +@-webkit-keyframes ball-scale {
  116 + 0% {
  117 + -webkit-transform: scale(0);
  118 + transform: scale(0); }
  119 + 100% {
  120 + -webkit-transform: scale(1);
  121 + transform: scale(1);
  122 + opacity: 0; } }
  123 +
  124 +@keyframes ball-scale {
  125 + 0% {
  126 + -webkit-transform: scale(0);
  127 + transform: scale(0); }
  128 + 100% {
  129 + -webkit-transform: scale(1);
  130 + transform: scale(1);
  131 + opacity: 0; } }
  132 +
  133 +.ball-scale > div {
  134 + background-color: #fff;
  135 + width: 15px;
  136 + height: 15px;
  137 + border-radius: 100%;
  138 + margin: 2px;
  139 + -webkit-animation-fill-mode: both;
  140 + animation-fill-mode: both;
  141 + display: inline-block;
  142 + height: 60px;
  143 + width: 60px;
  144 + -webkit-animation: ball-scale 1s 0s ease-in-out infinite;
  145 + animation: ball-scale 1s 0s ease-in-out infinite; }
  146 +
  147 +@keyframes ball-scale {
  148 + 0% {
  149 + -webkit-transform: scale(0);
  150 + transform: scale(0); }
  151 + 100% {
  152 + -webkit-transform: scale(1);
  153 + transform: scale(1);
  154 + opacity: 0; } }
  155 +
  156 +.ball-scale > div {
  157 + background-color: #fff;
  158 + width: 15px;
  159 + height: 15px;
  160 + border-radius: 100%;
  161 + margin: 2px;
  162 + -webkit-animation-fill-mode: both;
  163 + animation-fill-mode: both;
  164 + display: inline-block;
  165 + height: 60px;
  166 + width: 60px;
  167 + -webkit-animation: ball-scale 1s 0s ease-in-out infinite;
  168 + animation: ball-scale 1s 0s ease-in-out infinite; }
  169 +
  170 +.ball-scale-random {
  171 + width: 37px;
  172 + height: 40px; }
  173 + .ball-scale-random > div {
  174 + background-color: #fff;
  175 + width: 15px;
  176 + height: 15px;
  177 + border-radius: 100%;
  178 + margin: 2px;
  179 + -webkit-animation-fill-mode: both;
  180 + animation-fill-mode: both;
  181 + position: absolute;
  182 + display: inline-block;
  183 + height: 30px;
  184 + width: 30px;
  185 + -webkit-animation: ball-scale 1s 0s ease-in-out infinite;
  186 + animation: ball-scale 1s 0s ease-in-out infinite; }
  187 + .ball-scale-random > div:nth-child(1) {
  188 + margin-left: -7px;
  189 + -webkit-animation: ball-scale 1s 0.2s ease-in-out infinite;
  190 + animation: ball-scale 1s 0.2s ease-in-out infinite; }
  191 + .ball-scale-random > div:nth-child(3) {
  192 + margin-left: -2px;
  193 + margin-top: 9px;
  194 + -webkit-animation: ball-scale 1s 0.5s ease-in-out infinite;
  195 + animation: ball-scale 1s 0.5s ease-in-out infinite; }
  196 +
  197 +@-webkit-keyframes rotate {
  198 + 0% {
  199 + -webkit-transform: rotate(0deg);
  200 + transform: rotate(0deg); }
  201 + 50% {
  202 + -webkit-transform: rotate(180deg);
  203 + transform: rotate(180deg); }
  204 + 100% {
  205 + -webkit-transform: rotate(360deg);
  206 + transform: rotate(360deg); } }
  207 +
  208 +@keyframes rotate {
  209 + 0% {
  210 + -webkit-transform: rotate(0deg);
  211 + transform: rotate(0deg); }
  212 + 50% {
  213 + -webkit-transform: rotate(180deg);
  214 + transform: rotate(180deg); }
  215 + 100% {
  216 + -webkit-transform: rotate(360deg);
  217 + transform: rotate(360deg); } }
  218 +
  219 +.ball-rotate {
  220 + position: relative; }
  221 + .ball-rotate > div {
  222 + background-color: #fff;
  223 + width: 15px;
  224 + height: 15px;
  225 + border-radius: 100%;
  226 + margin: 2px;
  227 + -webkit-animation-fill-mode: both;
  228 + animation-fill-mode: both;
  229 + position: relative; }
  230 + .ball-rotate > div:first-child {
  231 + -webkit-animation: rotate 1s 0s cubic-bezier(0.7, -0.13, 0.22, 0.86) infinite;
  232 + animation: rotate 1s 0s cubic-bezier(0.7, -0.13, 0.22, 0.86) infinite; }
  233 + .ball-rotate > div:before, .ball-rotate > div:after {
  234 + background-color: #fff;
  235 + width: 15px;
  236 + height: 15px;
  237 + border-radius: 100%;
  238 + margin: 2px;
  239 + content: "";
  240 + position: absolute;
  241 + opacity: 0.8; }
  242 + .ball-rotate > div:before {
  243 + top: 0px;
  244 + left: -28px; }
  245 + .ball-rotate > div:after {
  246 + top: 0px;
  247 + left: 25px; }
  248 +
  249 +@keyframes rotate {
  250 + 0% {
  251 + -webkit-transform: rotate(0deg) scale(1);
  252 + transform: rotate(0deg) scale(1); }
  253 + 50% {
  254 + -webkit-transform: rotate(180deg) scale(0.6);
  255 + transform: rotate(180deg) scale(0.6); }
  256 + 100% {
  257 + -webkit-transform: rotate(360deg) scale(1);
  258 + transform: rotate(360deg) scale(1); } }
  259 +
  260 +.ball-clip-rotate > div {
  261 + background-color: #fff;
  262 + width: 15px;
  263 + height: 15px;
  264 + border-radius: 100%;
  265 + margin: 2px;
  266 + -webkit-animation-fill-mode: both;
  267 + animation-fill-mode: both;
  268 + border: 2px solid #fff;
  269 + border-bottom-color: transparent;
  270 + height: 25px;
  271 + width: 25px;
  272 + background: transparent !important;
  273 + display: inline-block;
  274 + -webkit-animation: rotate 0.75s 0s linear infinite;
  275 + animation: rotate 0.75s 0s linear infinite; }
  276 +
  277 +@keyframes rotate {
  278 + 0% {
  279 + -webkit-transform: rotate(0deg) scale(1);
  280 + transform: rotate(0deg) scale(1); }
  281 + 50% {
  282 + -webkit-transform: rotate(180deg) scale(0.6);
  283 + transform: rotate(180deg) scale(0.6); }
  284 + 100% {
  285 + -webkit-transform: rotate(360deg) scale(1);
  286 + transform: rotate(360deg) scale(1); } }
  287 +
  288 +@keyframes scale {
  289 + 30% {
  290 + -webkit-transform: scale(0.3);
  291 + transform: scale(0.3); }
  292 + 100% {
  293 + -webkit-transform: scale(1);
  294 + transform: scale(1); } }
  295 +
  296 +.ball-clip-rotate-pulse {
  297 + position: relative;
  298 + -webkit-transform: translateY(-15px);
  299 + -ms-transform: translateY(-15px);
  300 + transform: translateY(-15px); }
  301 + .ball-clip-rotate-pulse > div {
  302 + -webkit-animation-fill-mode: both;
  303 + animation-fill-mode: both;
  304 + position: absolute;
  305 + top: 0px;
  306 + left: 0px;
  307 + border-radius: 100%; }
  308 + .ball-clip-rotate-pulse > div:first-child {
  309 + background: #fff;
  310 + height: 16px;
  311 + width: 16px;
  312 + top: 7px;
  313 + left: -7px;
  314 + -webkit-animation: scale 1s 0s cubic-bezier(0.09, 0.57, 0.49, 0.9) infinite;
  315 + animation: scale 1s 0s cubic-bezier(0.09, 0.57, 0.49, 0.9) infinite; }
  316 + .ball-clip-rotate-pulse > div:last-child {
  317 + position: absolute;
  318 + border: 2px solid #fff;
  319 + width: 30px;
  320 + height: 30px;
  321 + left: -16px;
  322 + top: -2px;
  323 + background: transparent;
  324 + border: 2px solid;
  325 + border-color: #fff transparent #fff transparent;
  326 + -webkit-animation: rotate 1s 0s cubic-bezier(0.09, 0.57, 0.49, 0.9) infinite;
  327 + animation: rotate 1s 0s cubic-bezier(0.09, 0.57, 0.49, 0.9) infinite;
  328 + -webkit-animation-duration: 1s;
  329 + animation-duration: 1s; }
  330 +
  331 +@keyframes rotate {
  332 + 0% {
  333 + -webkit-transform: rotate(0deg) scale(1);
  334 + transform: rotate(0deg) scale(1); }
  335 + 50% {
  336 + -webkit-transform: rotate(180deg) scale(0.6);
  337 + transform: rotate(180deg) scale(0.6); }
  338 + 100% {
  339 + -webkit-transform: rotate(360deg) scale(1);
  340 + transform: rotate(360deg) scale(1); } }
  341 +
  342 +.ball-clip-rotate-multiple {
  343 + position: relative; }
  344 + .ball-clip-rotate-multiple > div {
  345 + -webkit-animation-fill-mode: both;
  346 + animation-fill-mode: both;
  347 + position: absolute;
  348 + left: -20px;
  349 + top: -20px;
  350 + border: 2px solid #fff;
  351 + border-bottom-color: transparent;
  352 + border-top-color: transparent;
  353 + border-radius: 100%;
  354 + height: 35px;
  355 + width: 35px;
  356 + -webkit-animation: rotate 1s 0s ease-in-out infinite;
  357 + animation: rotate 1s 0s ease-in-out infinite; }
  358 + .ball-clip-rotate-multiple > div:last-child {
  359 + display: inline-block;
  360 + top: -10px;
  361 + left: -10px;
  362 + width: 15px;
  363 + height: 15px;
  364 + -webkit-animation-duration: 0.5s;
  365 + animation-duration: 0.5s;
  366 + border-color: #fff transparent #fff transparent;
  367 + -webkit-animation-direction: reverse;
  368 + animation-direction: reverse; }
  369 +
  370 +@-webkit-keyframes ball-scale-ripple {
  371 + 0% {
  372 + -webkit-transform: scale(0.1);
  373 + transform: scale(0.1);
  374 + opacity: 1; }
  375 + 70% {
  376 + -webkit-transform: scale(1);
  377 + transform: scale(1);
  378 + opacity: 0.7; }
  379 + 100% {
  380 + opacity: 0.0; } }
  381 +
  382 +@keyframes ball-scale-ripple {
  383 + 0% {
  384 + -webkit-transform: scale(0.1);
  385 + transform: scale(0.1);
  386 + opacity: 1; }
  387 + 70% {
  388 + -webkit-transform: scale(1);
  389 + transform: scale(1);
  390 + opacity: 0.7; }
  391 + 100% {
  392 + opacity: 0.0; } }
  393 +
  394 +.ball-scale-ripple > div {
  395 + -webkit-animation-fill-mode: both;
  396 + animation-fill-mode: both;
  397 + height: 50px;
  398 + width: 50px;
  399 + border-radius: 100%;
  400 + border: 2px solid #fff;
  401 + -webkit-animation: ball-scale-ripple 1s 0s infinite cubic-bezier(0.21, 0.53, 0.56, 0.8);
  402 + animation: ball-scale-ripple 1s 0s infinite cubic-bezier(0.21, 0.53, 0.56, 0.8); }
  403 +
  404 +@-webkit-keyframes ball-scale-ripple-multiple {
  405 + 0% {
  406 + -webkit-transform: scale(0.1);
  407 + transform: scale(0.1);
  408 + opacity: 1; }
  409 + 70% {
  410 + -webkit-transform: scale(1);
  411 + transform: scale(1);
  412 + opacity: 0.7; }
  413 + 100% {
  414 + opacity: 0.0; } }
  415 +
  416 +@keyframes ball-scale-ripple-multiple {
  417 + 0% {
  418 + -webkit-transform: scale(0.1);
  419 + transform: scale(0.1);
  420 + opacity: 1; }
  421 + 70% {
  422 + -webkit-transform: scale(1);
  423 + transform: scale(1);
  424 + opacity: 0.7; }
  425 + 100% {
  426 + opacity: 0.0; } }
  427 +
  428 +.ball-scale-ripple-multiple {
  429 + position: relative;
  430 + -webkit-transform: translateY(-25px);
  431 + -ms-transform: translateY(-25px);
  432 + transform: translateY(-25px); }
  433 + .ball-scale-ripple-multiple > div:nth-child(0) {
  434 + -webkit-animation-delay: -0.8s;
  435 + animation-delay: -0.8s; }
  436 + .ball-scale-ripple-multiple > div:nth-child(1) {
  437 + -webkit-animation-delay: -0.6s;
  438 + animation-delay: -0.6s; }
  439 + .ball-scale-ripple-multiple > div:nth-child(2) {
  440 + -webkit-animation-delay: -0.4s;
  441 + animation-delay: -0.4s; }
  442 + .ball-scale-ripple-multiple > div:nth-child(3) {
  443 + -webkit-animation-delay: -0.2s;
  444 + animation-delay: -0.2s; }
  445 + .ball-scale-ripple-multiple > div {
  446 + -webkit-animation-fill-mode: both;
  447 + animation-fill-mode: both;
  448 + position: absolute;
  449 + top: -2px;
  450 + left: -26px;
  451 + width: 50px;
  452 + height: 50px;
  453 + border-radius: 100%;
  454 + border: 2px solid #fff;
  455 + -webkit-animation: ball-scale-ripple-multiple 1.25s 0s infinite cubic-bezier(0.21, 0.53, 0.56, 0.8);
  456 + animation: ball-scale-ripple-multiple 1.25s 0s infinite cubic-bezier(0.21, 0.53, 0.56, 0.8); }
  457 +
  458 +@-webkit-keyframes ball-beat {
  459 + 50% {
  460 + opacity: 0.2;
  461 + -webkit-transform: scale(0.75);
  462 + transform: scale(0.75); }
  463 + 100% {
  464 + opacity: 1;
  465 + -webkit-transform: scale(1);
  466 + transform: scale(1); } }
  467 +
  468 +@keyframes ball-beat {
  469 + 50% {
  470 + opacity: 0.2;
  471 + -webkit-transform: scale(0.75);
  472 + transform: scale(0.75); }
  473 + 100% {
  474 + opacity: 1;
  475 + -webkit-transform: scale(1);
  476 + transform: scale(1); } }
  477 +
  478 +.ball-beat > div {
  479 + background-color: #fff;
  480 + width: 15px;
  481 + height: 15px;
  482 + border-radius: 100%;
  483 + margin: 2px;
  484 + -webkit-animation-fill-mode: both;
  485 + animation-fill-mode: both;
  486 + display: inline-block;
  487 + -webkit-animation: ball-beat 0.7s 0s infinite linear;
  488 + animation: ball-beat 0.7s 0s infinite linear; }
  489 + .ball-beat > div:nth-child(2n-1) {
  490 + -webkit-animation-delay: -0.35s !important;
  491 + animation-delay: -0.35s !important; }
  492 +
  493 +@-webkit-keyframes ball-scale-multiple {
  494 + 0% {
  495 + -webkit-transform: scale(0);
  496 + transform: scale(0);
  497 + opacity: 0; }
  498 + 5% {
  499 + opacity: 1; }
  500 + 100% {
  501 + -webkit-transform: scale(1);
  502 + transform: scale(1);
  503 + opacity: 0; } }
  504 +
  505 +@keyframes ball-scale-multiple {
  506 + 0% {
  507 + -webkit-transform: scale(0);
  508 + transform: scale(0);
  509 + opacity: 0; }
  510 + 5% {
  511 + opacity: 1; }
  512 + 100% {
  513 + -webkit-transform: scale(1);
  514 + transform: scale(1);
  515 + opacity: 0; } }
  516 +
  517 +.ball-scale-multiple {
  518 + position: relative;
  519 + -webkit-transform: translateY(-30px);
  520 + -ms-transform: translateY(-30px);
  521 + transform: translateY(-30px); }
  522 + .ball-scale-multiple > div:nth-child(2) {
  523 + -webkit-animation-delay: -0.4s;
  524 + animation-delay: -0.4s; }
  525 + .ball-scale-multiple > div:nth-child(3) {
  526 + -webkit-animation-delay: -0.2s;
  527 + animation-delay: -0.2s; }
  528 + .ball-scale-multiple > div {
  529 + background-color: #fff;
  530 + width: 15px;
  531 + height: 15px;
  532 + border-radius: 100%;
  533 + margin: 2px;
  534 + -webkit-animation-fill-mode: both;
  535 + animation-fill-mode: both;
  536 + position: absolute;
  537 + left: -30px;
  538 + top: 0px;
  539 + opacity: 0;
  540 + margin: 0;
  541 + width: 60px;
  542 + height: 60px;
  543 + -webkit-animation: ball-scale-multiple 1s 0s linear infinite;
  544 + animation: ball-scale-multiple 1s 0s linear infinite; }
  545 +
  546 +@-webkit-keyframes ball-triangle-path-1 {
  547 + 33% {
  548 + -webkit-transform: translate(25px, -50px);
  549 + transform: translate(25px, -50px); }
  550 + 66% {
  551 + -webkit-transform: translate(50px, 0px);
  552 + transform: translate(50px, 0px); }
  553 + 100% {
  554 + -webkit-transform: translate(0px, 0px);
  555 + transform: translate(0px, 0px); } }
  556 +
  557 +@keyframes ball-triangle-path-1 {
  558 + 33% {
  559 + -webkit-transform: translate(25px, -50px);
  560 + transform: translate(25px, -50px); }
  561 + 66% {
  562 + -webkit-transform: translate(50px, 0px);
  563 + transform: translate(50px, 0px); }
  564 + 100% {
  565 + -webkit-transform: translate(0px, 0px);
  566 + transform: translate(0px, 0px); } }
  567 +
  568 +@-webkit-keyframes ball-triangle-path-2 {
  569 + 33% {
  570 + -webkit-transform: translate(25px, 50px);
  571 + transform: translate(25px, 50px); }
  572 + 66% {
  573 + -webkit-transform: translate(-25px, 50px);
  574 + transform: translate(-25px, 50px); }
  575 + 100% {
  576 + -webkit-transform: translate(0px, 0px);
  577 + transform: translate(0px, 0px); } }
  578 +
  579 +@keyframes ball-triangle-path-2 {
  580 + 33% {
  581 + -webkit-transform: translate(25px, 50px);
  582 + transform: translate(25px, 50px); }
  583 + 66% {
  584 + -webkit-transform: translate(-25px, 50px);
  585 + transform: translate(-25px, 50px); }
  586 + 100% {
  587 + -webkit-transform: translate(0px, 0px);
  588 + transform: translate(0px, 0px); } }
  589 +
  590 +@-webkit-keyframes ball-triangle-path-3 {
  591 + 33% {
  592 + -webkit-transform: translate(-50px, 0px);
  593 + transform: translate(-50px, 0px); }
  594 + 66% {
  595 + -webkit-transform: translate(-25px, -50px);
  596 + transform: translate(-25px, -50px); }
  597 + 100% {
  598 + -webkit-transform: translate(0px, 0px);
  599 + transform: translate(0px, 0px); } }
  600 +
  601 +@keyframes ball-triangle-path-3 {
  602 + 33% {
  603 + -webkit-transform: translate(-50px, 0px);
  604 + transform: translate(-50px, 0px); }
  605 + 66% {
  606 + -webkit-transform: translate(-25px, -50px);
  607 + transform: translate(-25px, -50px); }
  608 + 100% {
  609 + -webkit-transform: translate(0px, 0px);
  610 + transform: translate(0px, 0px); } }
  611 +
  612 +.ball-triangle-path {
  613 + position: relative;
  614 + -webkit-transform: translate(-29.994px, -37.50938px);
  615 + -ms-transform: translate(-29.994px, -37.50938px);
  616 + transform: translate(-29.994px, -37.50938px); }
  617 + .ball-triangle-path > div:nth-child(1) {
  618 + -webkit-animation-name: ball-triangle-path-1;
  619 + animation-name: ball-triangle-path-1;
  620 + -webkit-animation-delay: 0;
  621 + animation-delay: 0;
  622 + -webkit-animation-duration: 2s;
  623 + animation-duration: 2s;
  624 + -webkit-animation-timing-function: ease-in-out;
  625 + animation-timing-function: ease-in-out;
  626 + -webkit-animation-iteration-count: infinite;
  627 + animation-iteration-count: infinite; }
  628 + .ball-triangle-path > div:nth-child(2) {
  629 + -webkit-animation-name: ball-triangle-path-2;
  630 + animation-name: ball-triangle-path-2;
  631 + -webkit-animation-delay: 0;
  632 + animation-delay: 0;
  633 + -webkit-animation-duration: 2s;
  634 + animation-duration: 2s;
  635 + -webkit-animation-timing-function: ease-in-out;
  636 + animation-timing-function: ease-in-out;
  637 + -webkit-animation-iteration-count: infinite;
  638 + animation-iteration-count: infinite; }
  639 + .ball-triangle-path > div:nth-child(3) {
  640 + -webkit-animation-name: ball-triangle-path-3;
  641 + animation-name: ball-triangle-path-3;
  642 + -webkit-animation-delay: 0;
  643 + animation-delay: 0;
  644 + -webkit-animation-duration: 2s;
  645 + animation-duration: 2s;
  646 + -webkit-animation-timing-function: ease-in-out;
  647 + animation-timing-function: ease-in-out;
  648 + -webkit-animation-iteration-count: infinite;
  649 + animation-iteration-count: infinite; }
  650 + .ball-triangle-path > div {
  651 + -webkit-animation-fill-mode: both;
  652 + animation-fill-mode: both;
  653 + position: absolute;
  654 + width: 10px;
  655 + height: 10px;
  656 + border-radius: 100%;
  657 + border: 1px solid #fff; }
  658 + .ball-triangle-path > div:nth-of-type(1) {
  659 + top: 50px; }
  660 + .ball-triangle-path > div:nth-of-type(2) {
  661 + left: 25px; }
  662 + .ball-triangle-path > div:nth-of-type(3) {
  663 + top: 50px;
  664 + left: 50px; }
  665 +
  666 +@-webkit-keyframes ball-pulse-rise-even {
  667 + 0% {
  668 + -webkit-transform: scale(1.1);
  669 + transform: scale(1.1); }
  670 + 25% {
  671 + -webkit-transform: translateY(-30px);
  672 + transform: translateY(-30px); }
  673 + 50% {
  674 + -webkit-transform: scale(0.4);
  675 + transform: scale(0.4); }
  676 + 75% {
  677 + -webkit-transform: translateY(30px);
  678 + transform: translateY(30px); }
  679 + 100% {
  680 + -webkit-transform: translateY(0);
  681 + transform: translateY(0);
  682 + -webkit-transform: scale(1);
  683 + transform: scale(1); } }
  684 +
  685 +@keyframes ball-pulse-rise-even {
  686 + 0% {
  687 + -webkit-transform: scale(1.1);
  688 + transform: scale(1.1); }
  689 + 25% {
  690 + -webkit-transform: translateY(-30px);
  691 + transform: translateY(-30px); }
  692 + 50% {
  693 + -webkit-transform: scale(0.4);
  694 + transform: scale(0.4); }
  695 + 75% {
  696 + -webkit-transform: translateY(30px);
  697 + transform: translateY(30px); }
  698 + 100% {
  699 + -webkit-transform: translateY(0);
  700 + transform: translateY(0);
  701 + -webkit-transform: scale(1);
  702 + transform: scale(1); } }
  703 +
  704 +@-webkit-keyframes ball-pulse-rise-odd {
  705 + 0% {
  706 + -webkit-transform: scale(0.4);
  707 + transform: scale(0.4); }
  708 + 25% {
  709 + -webkit-transform: translateY(30px);
  710 + transform: translateY(30px); }
  711 + 50% {
  712 + -webkit-transform: scale(1.1);
  713 + transform: scale(1.1); }
  714 + 75% {
  715 + -webkit-transform: translateY(-30px);
  716 + transform: translateY(-30px); }
  717 + 100% {
  718 + -webkit-transform: translateY(0);
  719 + transform: translateY(0);
  720 + -webkit-transform: scale(0.75);
  721 + transform: scale(0.75); } }
  722 +
  723 +@keyframes ball-pulse-rise-odd {
  724 + 0% {
  725 + -webkit-transform: scale(0.4);
  726 + transform: scale(0.4); }
  727 + 25% {
  728 + -webkit-transform: translateY(30px);
  729 + transform: translateY(30px); }
  730 + 50% {
  731 + -webkit-transform: scale(1.1);
  732 + transform: scale(1.1); }
  733 + 75% {
  734 + -webkit-transform: translateY(-30px);
  735 + transform: translateY(-30px); }
  736 + 100% {
  737 + -webkit-transform: translateY(0);
  738 + transform: translateY(0);
  739 + -webkit-transform: scale(0.75);
  740 + transform: scale(0.75); } }
  741 +
  742 +.ball-pulse-rise > div {
  743 + background-color: #fff;
  744 + width: 15px;
  745 + height: 15px;
  746 + border-radius: 100%;
  747 + margin: 2px;
  748 + -webkit-animation-fill-mode: both;
  749 + animation-fill-mode: both;
  750 + display: inline-block;
  751 + -webkit-animation-duration: 1s;
  752 + animation-duration: 1s;
  753 + -webkit-animation-timing-function: cubic-bezier(0.15, 0.46, 0.9, 0.6);
  754 + animation-timing-function: cubic-bezier(0.15, 0.46, 0.9, 0.6);
  755 + -webkit-animation-iteration-count: infinite;
  756 + animation-iteration-count: infinite;
  757 + -webkit-animation-delay: 0;
  758 + animation-delay: 0; }
  759 + .ball-pulse-rise > div:nth-child(2n) {
  760 + -webkit-animation-name: ball-pulse-rise-even;
  761 + animation-name: ball-pulse-rise-even; }
  762 + .ball-pulse-rise > div:nth-child(2n-1) {
  763 + -webkit-animation-name: ball-pulse-rise-odd;
  764 + animation-name: ball-pulse-rise-odd; }
  765 +
  766 +@-webkit-keyframes ball-grid-beat {
  767 + 50% {
  768 + opacity: 0.7; }
  769 + 100% {
  770 + opacity: 1; } }
  771 +
  772 +@keyframes ball-grid-beat {
  773 + 50% {
  774 + opacity: 0.7; }
  775 + 100% {
  776 + opacity: 1; } }
  777 +
  778 +.ball-grid-beat {
  779 + width: 57px; }
  780 + .ball-grid-beat > div:nth-child(1) {
  781 + -webkit-animation-delay: 0.44s;
  782 + animation-delay: 0.44s;
  783 + -webkit-animation-duration: 1.27s;
  784 + animation-duration: 1.27s; }
  785 + .ball-grid-beat > div:nth-child(2) {
  786 + -webkit-animation-delay: 0.2s;
  787 + animation-delay: 0.2s;
  788 + -webkit-animation-duration: 1.52s;
  789 + animation-duration: 1.52s; }
  790 + .ball-grid-beat > div:nth-child(3) {
  791 + -webkit-animation-delay: 0.14s;
  792 + animation-delay: 0.14s;
  793 + -webkit-animation-duration: 0.61s;
  794 + animation-duration: 0.61s; }
  795 + .ball-grid-beat > div:nth-child(4) {
  796 + -webkit-animation-delay: 0.15s;
  797 + animation-delay: 0.15s;
  798 + -webkit-animation-duration: 0.82s;
  799 + animation-duration: 0.82s; }
  800 + .ball-grid-beat > div:nth-child(5) {
  801 + -webkit-animation-delay: -0.01s;
  802 + animation-delay: -0.01s;
  803 + -webkit-animation-duration: 1.24s;
  804 + animation-duration: 1.24s; }
  805 + .ball-grid-beat > div:nth-child(6) {
  806 + -webkit-animation-delay: -0.07s;
  807 + animation-delay: -0.07s;
  808 + -webkit-animation-duration: 1.35s;
  809 + animation-duration: 1.35s; }
  810 + .ball-grid-beat > div:nth-child(7) {
  811 + -webkit-animation-delay: 0.29s;
  812 + animation-delay: 0.29s;
  813 + -webkit-animation-duration: 1.44s;
  814 + animation-duration: 1.44s; }
  815 + .ball-grid-beat > div:nth-child(8) {
  816 + -webkit-animation-delay: 0.63s;
  817 + animation-delay: 0.63s;
  818 + -webkit-animation-duration: 1.19s;
  819 + animation-duration: 1.19s; }
  820 + .ball-grid-beat > div:nth-child(9) {
  821 + -webkit-animation-delay: -0.18s;
  822 + animation-delay: -0.18s;
  823 + -webkit-animation-duration: 1.48s;
  824 + animation-duration: 1.48s; }
  825 + .ball-grid-beat > div {
  826 + background-color: #fff;
  827 + width: 15px;
  828 + height: 15px;
  829 + border-radius: 100%;
  830 + margin: 2px;
  831 + -webkit-animation-fill-mode: both;
  832 + animation-fill-mode: both;
  833 + display: inline-block;
  834 + float: left;
  835 + -webkit-animation-name: ball-grid-beat;
  836 + animation-name: ball-grid-beat;
  837 + -webkit-animation-iteration-count: infinite;
  838 + animation-iteration-count: infinite;
  839 + -webkit-animation-delay: 0;
  840 + animation-delay: 0; }
  841 +
  842 +@-webkit-keyframes ball-grid-pulse {
  843 + 0% {
  844 + -webkit-transform: scale(1);
  845 + transform: scale(1); }
  846 + 50% {
  847 + -webkit-transform: scale(0.5);
  848 + transform: scale(0.5);
  849 + opacity: 0.7; }
  850 + 100% {
  851 + -webkit-transform: scale(1);
  852 + transform: scale(1);
  853 + opacity: 1; } }
  854 +
  855 +@keyframes ball-grid-pulse {
  856 + 0% {
  857 + -webkit-transform: scale(1);
  858 + transform: scale(1); }
  859 + 50% {
  860 + -webkit-transform: scale(0.5);
  861 + transform: scale(0.5);
  862 + opacity: 0.7; }
  863 + 100% {
  864 + -webkit-transform: scale(1);
  865 + transform: scale(1);
  866 + opacity: 1; } }
  867 +
  868 +.ball-grid-pulse {
  869 + width: 57px; }
  870 + .ball-grid-pulse > div:nth-child(1) {
  871 + -webkit-animation-delay: 0.58s;
  872 + animation-delay: 0.58s;
  873 + -webkit-animation-duration: 0.9s;
  874 + animation-duration: 0.9s; }
  875 + .ball-grid-pulse > div:nth-child(2) {
  876 + -webkit-animation-delay: 0.01s;
  877 + animation-delay: 0.01s;
  878 + -webkit-animation-duration: 0.94s;
  879 + animation-duration: 0.94s; }
  880 + .ball-grid-pulse > div:nth-child(3) {
  881 + -webkit-animation-delay: 0.25s;
  882 + animation-delay: 0.25s;
  883 + -webkit-animation-duration: 1.43s;
  884 + animation-duration: 1.43s; }
  885 + .ball-grid-pulse > div:nth-child(4) {
  886 + -webkit-animation-delay: -0.03s;
  887 + animation-delay: -0.03s;
  888 + -webkit-animation-duration: 0.74s;
  889 + animation-duration: 0.74s; }
  890 + .ball-grid-pulse > div:nth-child(5) {
  891 + -webkit-animation-delay: 0.21s;
  892 + animation-delay: 0.21s;
  893 + -webkit-animation-duration: 0.68s;
  894 + animation-duration: 0.68s; }
  895 + .ball-grid-pulse > div:nth-child(6) {
  896 + -webkit-animation-delay: 0.25s;
  897 + animation-delay: 0.25s;
  898 + -webkit-animation-duration: 1.17s;
  899 + animation-duration: 1.17s; }
  900 + .ball-grid-pulse > div:nth-child(7) {
  901 + -webkit-animation-delay: 0.46s;
  902 + animation-delay: 0.46s;
  903 + -webkit-animation-duration: 1.41s;
  904 + animation-duration: 1.41s; }
  905 + .ball-grid-pulse > div:nth-child(8) {
  906 + -webkit-animation-delay: 0.02s;
  907 + animation-delay: 0.02s;
  908 + -webkit-animation-duration: 1.56s;
  909 + animation-duration: 1.56s; }
  910 + .ball-grid-pulse > div:nth-child(9) {
  911 + -webkit-animation-delay: 0.13s;
  912 + animation-delay: 0.13s;
  913 + -webkit-animation-duration: 0.78s;
  914 + animation-duration: 0.78s; }
  915 + .ball-grid-pulse > div {
  916 + background-color: #fff;
  917 + width: 15px;
  918 + height: 15px;
  919 + border-radius: 100%;
  920 + margin: 2px;
  921 + -webkit-animation-fill-mode: both;
  922 + animation-fill-mode: both;
  923 + display: inline-block;
  924 + float: left;
  925 + -webkit-animation-name: ball-grid-pulse;
  926 + animation-name: ball-grid-pulse;
  927 + -webkit-animation-iteration-count: infinite;
  928 + animation-iteration-count: infinite;
  929 + -webkit-animation-delay: 0;
  930 + animation-delay: 0; }
  931 +
  932 +@-webkit-keyframes ball-spin-fade-loader {
  933 + 50% {
  934 + opacity: 0.3;
  935 + -webkit-transform: scale(0.4);
  936 + transform: scale(0.4); }
  937 + 100% {
  938 + opacity: 1;
  939 + -webkit-transform: scale(1);
  940 + transform: scale(1); } }
  941 +
  942 +@keyframes ball-spin-fade-loader {
  943 + 50% {
  944 + opacity: 0.3;
  945 + -webkit-transform: scale(0.4);
  946 + transform: scale(0.4); }
  947 + 100% {
  948 + opacity: 1;
  949 + -webkit-transform: scale(1);
  950 + transform: scale(1); } }
  951 +
  952 +.ball-spin-fade-loader {
  953 + position: relative;
  954 + top: -10px;
  955 + left: -10px; }
  956 + .ball-spin-fade-loader > div:nth-child(1) {
  957 + top: 25px;
  958 + left: 0;
  959 + -webkit-animation: ball-spin-fade-loader 1s -0.96s infinite linear;
  960 + animation: ball-spin-fade-loader 1s -0.96s infinite linear; }
  961 + .ball-spin-fade-loader > div:nth-child(2) {
  962 + top: 17.04545px;
  963 + left: 17.04545px;
  964 + -webkit-animation: ball-spin-fade-loader 1s -0.84s infinite linear;
  965 + animation: ball-spin-fade-loader 1s -0.84s infinite linear; }
  966 + .ball-spin-fade-loader > div:nth-child(3) {
  967 + top: 0;
  968 + left: 25px;
  969 + -webkit-animation: ball-spin-fade-loader 1s -0.72s infinite linear;
  970 + animation: ball-spin-fade-loader 1s -0.72s infinite linear; }
  971 + .ball-spin-fade-loader > div:nth-child(4) {
  972 + top: -17.04545px;
  973 + left: 17.04545px;
  974 + -webkit-animation: ball-spin-fade-loader 1s -0.6s infinite linear;
  975 + animation: ball-spin-fade-loader 1s -0.6s infinite linear; }
  976 + .ball-spin-fade-loader > div:nth-child(5) {
  977 + top: -25px;
  978 + left: 0;
  979 + -webkit-animation: ball-spin-fade-loader 1s -0.48s infinite linear;
  980 + animation: ball-spin-fade-loader 1s -0.48s infinite linear; }
  981 + .ball-spin-fade-loader > div:nth-child(6) {
  982 + top: -17.04545px;
  983 + left: -17.04545px;
  984 + -webkit-animation: ball-spin-fade-loader 1s -0.36s infinite linear;
  985 + animation: ball-spin-fade-loader 1s -0.36s infinite linear; }
  986 + .ball-spin-fade-loader > div:nth-child(7) {
  987 + top: 0;
  988 + left: -25px;
  989 + -webkit-animation: ball-spin-fade-loader 1s -0.24s infinite linear;
  990 + animation: ball-spin-fade-loader 1s -0.24s infinite linear; }
  991 + .ball-spin-fade-loader > div:nth-child(8) {
  992 + top: 17.04545px;
  993 + left: -17.04545px;
  994 + -webkit-animation: ball-spin-fade-loader 1s -0.12s infinite linear;
  995 + animation: ball-spin-fade-loader 1s -0.12s infinite linear; }
  996 + .ball-spin-fade-loader > div {
  997 + background-color: #fff;
  998 + width: 15px;
  999 + height: 15px;
  1000 + border-radius: 100%;
  1001 + margin: 2px;
  1002 + -webkit-animation-fill-mode: both;
  1003 + animation-fill-mode: both;
  1004 + position: absolute; }
  1005 +
  1006 +@-webkit-keyframes ball-spin-loader {
  1007 + 75% {
  1008 + opacity: 0.2; }
  1009 + 100% {
  1010 + opacity: 1; } }
  1011 +
  1012 +@keyframes ball-spin-loader {
  1013 + 75% {
  1014 + opacity: 0.2; }
  1015 + 100% {
  1016 + opacity: 1; } }
  1017 +
  1018 +.ball-spin-loader {
  1019 + position: relative; }
  1020 + .ball-spin-loader > span:nth-child(1) {
  1021 + top: 45px;
  1022 + left: 0;
  1023 + -webkit-animation: ball-spin-loader 2s 0.9s infinite linear;
  1024 + animation: ball-spin-loader 2s 0.9s infinite linear; }
  1025 + .ball-spin-loader > span:nth-child(2) {
  1026 + top: 30.68182px;
  1027 + left: 30.68182px;
  1028 + -webkit-animation: ball-spin-loader 2s 1.8s infinite linear;
  1029 + animation: ball-spin-loader 2s 1.8s infinite linear; }
  1030 + .ball-spin-loader > span:nth-child(3) {
  1031 + top: 0;
  1032 + left: 45px;
  1033 + -webkit-animation: ball-spin-loader 2s 2.7s infinite linear;
  1034 + animation: ball-spin-loader 2s 2.7s infinite linear; }
  1035 + .ball-spin-loader > span:nth-child(4) {
  1036 + top: -30.68182px;
  1037 + left: 30.68182px;
  1038 + -webkit-animation: ball-spin-loader 2s 3.6s infinite linear;
  1039 + animation: ball-spin-loader 2s 3.6s infinite linear; }
  1040 + .ball-spin-loader > span:nth-child(5) {
  1041 + top: -45px;
  1042 + left: 0;
  1043 + -webkit-animation: ball-spin-loader 2s 4.5s infinite linear;
  1044 + animation: ball-spin-loader 2s 4.5s infinite linear; }
  1045 + .ball-spin-loader > span:nth-child(6) {
  1046 + top: -30.68182px;
  1047 + left: -30.68182px;
  1048 + -webkit-animation: ball-spin-loader 2s 5.4s infinite linear;
  1049 + animation: ball-spin-loader 2s 5.4s infinite linear; }
  1050 + .ball-spin-loader > span:nth-child(7) {
  1051 + top: 0;
  1052 + left: -45px;
  1053 + -webkit-animation: ball-spin-loader 2s 6.3s infinite linear;
  1054 + animation: ball-spin-loader 2s 6.3s infinite linear; }
  1055 + .ball-spin-loader > span:nth-child(8) {
  1056 + top: 30.68182px;
  1057 + left: -30.68182px;
  1058 + -webkit-animation: ball-spin-loader 2s 7.2s infinite linear;
  1059 + animation: ball-spin-loader 2s 7.2s infinite linear; }
  1060 + .ball-spin-loader > div {
  1061 + -webkit-animation-fill-mode: both;
  1062 + animation-fill-mode: both;
  1063 + position: absolute;
  1064 + width: 15px;
  1065 + height: 15px;
  1066 + border-radius: 100%;
  1067 + background: green; }
  1068 +
  1069 +@-webkit-keyframes ball-zig {
  1070 + 33% {
  1071 + -webkit-transform: translate(-15px, -30px);
  1072 + transform: translate(-15px, -30px); }
  1073 + 66% {
  1074 + -webkit-transform: translate(15px, -30px);
  1075 + transform: translate(15px, -30px); }
  1076 + 100% {
  1077 + -webkit-transform: translate(0, 0);
  1078 + transform: translate(0, 0); } }
  1079 +
  1080 +@keyframes ball-zig {
  1081 + 33% {
  1082 + -webkit-transform: translate(-15px, -30px);
  1083 + transform: translate(-15px, -30px); }
  1084 + 66% {
  1085 + -webkit-transform: translate(15px, -30px);
  1086 + transform: translate(15px, -30px); }
  1087 + 100% {
  1088 + -webkit-transform: translate(0, 0);
  1089 + transform: translate(0, 0); } }
  1090 +
  1091 +@-webkit-keyframes ball-zag {
  1092 + 33% {
  1093 + -webkit-transform: translate(15px, 30px);
  1094 + transform: translate(15px, 30px); }
  1095 + 66% {
  1096 + -webkit-transform: translate(-15px, 30px);
  1097 + transform: translate(-15px, 30px); }
  1098 + 100% {
  1099 + -webkit-transform: translate(0, 0);
  1100 + transform: translate(0, 0); } }
  1101 +
  1102 +@keyframes ball-zag {
  1103 + 33% {
  1104 + -webkit-transform: translate(15px, 30px);
  1105 + transform: translate(15px, 30px); }
  1106 + 66% {
  1107 + -webkit-transform: translate(-15px, 30px);
  1108 + transform: translate(-15px, 30px); }
  1109 + 100% {
  1110 + -webkit-transform: translate(0, 0);
  1111 + transform: translate(0, 0); } }
  1112 +
  1113 +.ball-zig-zag {
  1114 + position: relative;
  1115 + -webkit-transform: translate(-15px, -15px);
  1116 + -ms-transform: translate(-15px, -15px);
  1117 + transform: translate(-15px, -15px); }
  1118 + .ball-zig-zag > div {
  1119 + background-color: #fff;
  1120 + width: 15px;
  1121 + height: 15px;
  1122 + border-radius: 100%;
  1123 + margin: 2px;
  1124 + -webkit-animation-fill-mode: both;
  1125 + animation-fill-mode: both;
  1126 + position: absolute;
  1127 + margin-left: 15px;
  1128 + top: 4px;
  1129 + left: -7px; }
  1130 + .ball-zig-zag > div:first-child {
  1131 + -webkit-animation: ball-zig 0.7s 0s infinite linear;
  1132 + animation: ball-zig 0.7s 0s infinite linear; }
  1133 + .ball-zig-zag > div:last-child {
  1134 + -webkit-animation: ball-zag 0.7s 0s infinite linear;
  1135 + animation: ball-zag 0.7s 0s infinite linear; }
  1136 +
  1137 +@-webkit-keyframes ball-zig-deflect {
  1138 + 17% {
  1139 + -webkit-transform: translate(-15px, -30px);
  1140 + transform: translate(-15px, -30px); }
  1141 + 34% {
  1142 + -webkit-transform: translate(15px, -30px);
  1143 + transform: translate(15px, -30px); }
  1144 + 50% {
  1145 + -webkit-transform: translate(0, 0);
  1146 + transform: translate(0, 0); }
  1147 + 67% {
  1148 + -webkit-transform: translate(15px, -30px);
  1149 + transform: translate(15px, -30px); }
  1150 + 84% {
  1151 + -webkit-transform: translate(-15px, -30px);
  1152 + transform: translate(-15px, -30px); }
  1153 + 100% {
  1154 + -webkit-transform: translate(0, 0);
  1155 + transform: translate(0, 0); } }
  1156 +
  1157 +@keyframes ball-zig-deflect {
  1158 + 17% {
  1159 + -webkit-transform: translate(-15px, -30px);
  1160 + transform: translate(-15px, -30px); }
  1161 + 34% {
  1162 + -webkit-transform: translate(15px, -30px);
  1163 + transform: translate(15px, -30px); }
  1164 + 50% {
  1165 + -webkit-transform: translate(0, 0);
  1166 + transform: translate(0, 0); }
  1167 + 67% {
  1168 + -webkit-transform: translate(15px, -30px);
  1169 + transform: translate(15px, -30px); }
  1170 + 84% {
  1171 + -webkit-transform: translate(-15px, -30px);
  1172 + transform: translate(-15px, -30px); }
  1173 + 100% {
  1174 + -webkit-transform: translate(0, 0);
  1175 + transform: translate(0, 0); } }
  1176 +
  1177 +@-webkit-keyframes ball-zag-deflect {
  1178 + 17% {
  1179 + -webkit-transform: translate(15px, 30px);
  1180 + transform: translate(15px, 30px); }
  1181 + 34% {
  1182 + -webkit-transform: translate(-15px, 30px);
  1183 + transform: translate(-15px, 30px); }
  1184 + 50% {
  1185 + -webkit-transform: translate(0, 0);
  1186 + transform: translate(0, 0); }
  1187 + 67% {
  1188 + -webkit-transform: translate(-15px, 30px);
  1189 + transform: translate(-15px, 30px); }
  1190 + 84% {
  1191 + -webkit-transform: translate(15px, 30px);
  1192 + transform: translate(15px, 30px); }
  1193 + 100% {
  1194 + -webkit-transform: translate(0, 0);
  1195 + transform: translate(0, 0); } }
  1196 +
  1197 +@keyframes ball-zag-deflect {
  1198 + 17% {
  1199 + -webkit-transform: translate(15px, 30px);
  1200 + transform: translate(15px, 30px); }
  1201 + 34% {
  1202 + -webkit-transform: translate(-15px, 30px);
  1203 + transform: translate(-15px, 30px); }
  1204 + 50% {
  1205 + -webkit-transform: translate(0, 0);
  1206 + transform: translate(0, 0); }
  1207 + 67% {
  1208 + -webkit-transform: translate(-15px, 30px);
  1209 + transform: translate(-15px, 30px); }
  1210 + 84% {
  1211 + -webkit-transform: translate(15px, 30px);
  1212 + transform: translate(15px, 30px); }
  1213 + 100% {
  1214 + -webkit-transform: translate(0, 0);
  1215 + transform: translate(0, 0); } }
  1216 +
  1217 +.ball-zig-zag-deflect {
  1218 + position: relative;
  1219 + -webkit-transform: translate(-15px, -15px);
  1220 + -ms-transform: translate(-15px, -15px);
  1221 + transform: translate(-15px, -15px); }
  1222 + .ball-zig-zag-deflect > div {
  1223 + background-color: #fff;
  1224 + width: 15px;
  1225 + height: 15px;
  1226 + border-radius: 100%;
  1227 + margin: 2px;
  1228 + -webkit-animation-fill-mode: both;
  1229 + animation-fill-mode: both;
  1230 + position: absolute;
  1231 + margin-left: 15px;
  1232 + top: 4px;
  1233 + left: -7px; }
  1234 + .ball-zig-zag-deflect > div:first-child {
  1235 + -webkit-animation: ball-zig-deflect 1.5s 0s infinite linear;
  1236 + animation: ball-zig-deflect 1.5s 0s infinite linear; }
  1237 + .ball-zig-zag-deflect > div:last-child {
  1238 + -webkit-animation: ball-zag-deflect 1.5s 0s infinite linear;
  1239 + animation: ball-zag-deflect 1.5s 0s infinite linear; }
  1240 +
  1241 +/**
  1242 + * Lines
  1243 + */
  1244 +@-webkit-keyframes line-scale {
  1245 + 0% {
  1246 + -webkit-transform: scaley(1);
  1247 + transform: scaley(1); }
  1248 + 50% {
  1249 + -webkit-transform: scaley(0.4);
  1250 + transform: scaley(0.4); }
  1251 + 100% {
  1252 + -webkit-transform: scaley(1);
  1253 + transform: scaley(1); } }
  1254 +@keyframes line-scale {
  1255 + 0% {
  1256 + -webkit-transform: scaley(1);
  1257 + transform: scaley(1); }
  1258 + 50% {
  1259 + -webkit-transform: scaley(0.4);
  1260 + transform: scaley(0.4); }
  1261 + 100% {
  1262 + -webkit-transform: scaley(1);
  1263 + transform: scaley(1); } }
  1264 +
  1265 +.line-scale > div:nth-child(1) {
  1266 + -webkit-animation: line-scale 1s -0.4s infinite cubic-bezier(0.2, 0.68, 0.18, 1.08);
  1267 + animation: line-scale 1s -0.4s infinite cubic-bezier(0.2, 0.68, 0.18, 1.08); }
  1268 +
  1269 +.line-scale > div:nth-child(2) {
  1270 + -webkit-animation: line-scale 1s -0.3s infinite cubic-bezier(0.2, 0.68, 0.18, 1.08);
  1271 + animation: line-scale 1s -0.3s infinite cubic-bezier(0.2, 0.68, 0.18, 1.08); }
  1272 +
  1273 +.line-scale > div:nth-child(3) {
  1274 + -webkit-animation: line-scale 1s -0.2s infinite cubic-bezier(0.2, 0.68, 0.18, 1.08);
  1275 + animation: line-scale 1s -0.2s infinite cubic-bezier(0.2, 0.68, 0.18, 1.08); }
  1276 +
  1277 +.line-scale > div:nth-child(4) {
  1278 + -webkit-animation: line-scale 1s -0.1s infinite cubic-bezier(0.2, 0.68, 0.18, 1.08);
  1279 + animation: line-scale 1s -0.1s infinite cubic-bezier(0.2, 0.68, 0.18, 1.08); }
  1280 +
  1281 +.line-scale > div:nth-child(5) {
  1282 + -webkit-animation: line-scale 1s 0s infinite cubic-bezier(0.2, 0.68, 0.18, 1.08);
  1283 + animation: line-scale 1s 0s infinite cubic-bezier(0.2, 0.68, 0.18, 1.08); }
  1284 +
  1285 +.line-scale > div {
  1286 + background-color: #fff;
  1287 + width: 4px;
  1288 + height: 35px;
  1289 + border-radius: 2px;
  1290 + margin: 2px;
  1291 + -webkit-animation-fill-mode: both;
  1292 + animation-fill-mode: both;
  1293 + display: inline-block; }
  1294 +
  1295 +@-webkit-keyframes line-scale-party {
  1296 + 0% {
  1297 + -webkit-transform: scale(1);
  1298 + transform: scale(1); }
  1299 + 50% {
  1300 + -webkit-transform: scale(0.5);
  1301 + transform: scale(0.5); }
  1302 + 100% {
  1303 + -webkit-transform: scale(1);
  1304 + transform: scale(1); } }
  1305 +
  1306 +@keyframes line-scale-party {
  1307 + 0% {
  1308 + -webkit-transform: scale(1);
  1309 + transform: scale(1); }
  1310 + 50% {
  1311 + -webkit-transform: scale(0.5);
  1312 + transform: scale(0.5); }
  1313 + 100% {
  1314 + -webkit-transform: scale(1);
  1315 + transform: scale(1); } }
  1316 +
  1317 +.line-scale-party > div:nth-child(1) {
  1318 + -webkit-animation-delay: -0.09s;
  1319 + animation-delay: -0.09s;
  1320 + -webkit-animation-duration: 0.83s;
  1321 + animation-duration: 0.83s; }
  1322 +
  1323 +.line-scale-party > div:nth-child(2) {
  1324 + -webkit-animation-delay: 0.33s;
  1325 + animation-delay: 0.33s;
  1326 + -webkit-animation-duration: 0.64s;
  1327 + animation-duration: 0.64s; }
  1328 +
  1329 +.line-scale-party > div:nth-child(3) {
  1330 + -webkit-animation-delay: 0.32s;
  1331 + animation-delay: 0.32s;
  1332 + -webkit-animation-duration: 0.39s;
  1333 + animation-duration: 0.39s; }
  1334 +
  1335 +.line-scale-party > div:nth-child(4) {
  1336 + -webkit-animation-delay: 0.47s;
  1337 + animation-delay: 0.47s;
  1338 + -webkit-animation-duration: 0.52s;
  1339 + animation-duration: 0.52s; }
  1340 +
  1341 +.line-scale-party > div {
  1342 + background-color: #fff;
  1343 + width: 4px;
  1344 + height: 35px;
  1345 + border-radius: 2px;
  1346 + margin: 2px;
  1347 + -webkit-animation-fill-mode: both;
  1348 + animation-fill-mode: both;
  1349 + display: inline-block;
  1350 + -webkit-animation-name: line-scale-party;
  1351 + animation-name: line-scale-party;
  1352 + -webkit-animation-iteration-count: infinite;
  1353 + animation-iteration-count: infinite;
  1354 + -webkit-animation-delay: 0;
  1355 + animation-delay: 0; }
  1356 +
  1357 +@-webkit-keyframes line-scale-pulse-out {
  1358 + 0% {
  1359 + -webkit-transform: scaley(1);
  1360 + transform: scaley(1); }
  1361 + 50% {
  1362 + -webkit-transform: scaley(0.4);
  1363 + transform: scaley(0.4); }
  1364 + 100% {
  1365 + -webkit-transform: scaley(1);
  1366 + transform: scaley(1); } }
  1367 +
  1368 +@keyframes line-scale-pulse-out {
  1369 + 0% {
  1370 + -webkit-transform: scaley(1);
  1371 + transform: scaley(1); }
  1372 + 50% {
  1373 + -webkit-transform: scaley(0.4);
  1374 + transform: scaley(0.4); }
  1375 + 100% {
  1376 + -webkit-transform: scaley(1);
  1377 + transform: scaley(1); } }
  1378 +
  1379 +.line-scale-pulse-out > div {
  1380 + background-color: #fff;
  1381 + width: 4px;
  1382 + height: 35px;
  1383 + border-radius: 2px;
  1384 + margin: 2px;
  1385 + -webkit-animation-fill-mode: both;
  1386 + animation-fill-mode: both;
  1387 + display: inline-block;
  1388 + -webkit-animation: line-scale-pulse-out 0.9s -0.6s infinite cubic-bezier(0.85, 0.25, 0.37, 0.85);
  1389 + animation: line-scale-pulse-out 0.9s -0.6s infinite cubic-bezier(0.85, 0.25, 0.37, 0.85); }
  1390 + .line-scale-pulse-out > div:nth-child(2), .line-scale-pulse-out > div:nth-child(4) {
  1391 + -webkit-animation-delay: -0.4s !important;
  1392 + animation-delay: -0.4s !important; }
  1393 + .line-scale-pulse-out > div:nth-child(1), .line-scale-pulse-out > div:nth-child(5) {
  1394 + -webkit-animation-delay: -0.2s !important;
  1395 + animation-delay: -0.2s !important; }
  1396 +
  1397 +@-webkit-keyframes line-scale-pulse-out-rapid {
  1398 + 0% {
  1399 + -webkit-transform: scaley(1);
  1400 + transform: scaley(1); }
  1401 + 80% {
  1402 + -webkit-transform: scaley(0.3);
  1403 + transform: scaley(0.3); }
  1404 + 90% {
  1405 + -webkit-transform: scaley(1);
  1406 + transform: scaley(1); } }
  1407 +
  1408 +@keyframes line-scale-pulse-out-rapid {
  1409 + 0% {
  1410 + -webkit-transform: scaley(1);
  1411 + transform: scaley(1); }
  1412 + 80% {
  1413 + -webkit-transform: scaley(0.3);
  1414 + transform: scaley(0.3); }
  1415 + 90% {
  1416 + -webkit-transform: scaley(1);
  1417 + transform: scaley(1); } }
  1418 +
  1419 +.line-scale-pulse-out-rapid > div {
  1420 + background-color: #fff;
  1421 + width: 4px;
  1422 + height: 35px;
  1423 + border-radius: 2px;
  1424 + margin: 2px;
  1425 + -webkit-animation-fill-mode: both;
  1426 + animation-fill-mode: both;
  1427 + display: inline-block;
  1428 + -webkit-animation: line-scale-pulse-out-rapid 0.9s -0.5s infinite cubic-bezier(0.11, 0.49, 0.38, 0.78);
  1429 + animation: line-scale-pulse-out-rapid 0.9s -0.5s infinite cubic-bezier(0.11, 0.49, 0.38, 0.78); }
  1430 + .line-scale-pulse-out-rapid > div:nth-child(2), .line-scale-pulse-out-rapid > div:nth-child(4) {
  1431 + -webkit-animation-delay: -0.25s !important;
  1432 + animation-delay: -0.25s !important; }
  1433 + .line-scale-pulse-out-rapid > div:nth-child(1), .line-scale-pulse-out-rapid > div:nth-child(5) {
  1434 + -webkit-animation-delay: 0s !important;
  1435 + animation-delay: 0s !important; }
  1436 +
  1437 +@-webkit-keyframes line-spin-fade-loader {
  1438 + 50% {
  1439 + opacity: 0.3; }
  1440 + 100% {
  1441 + opacity: 1; } }
  1442 +
  1443 +@keyframes line-spin-fade-loader {
  1444 + 50% {
  1445 + opacity: 0.3; }
  1446 + 100% {
  1447 + opacity: 1; } }
  1448 +
  1449 +.line-spin-fade-loader {
  1450 + position: relative;
  1451 + top: -10px;
  1452 + left: -4px; }
  1453 + .line-spin-fade-loader > div:nth-child(1) {
  1454 + top: 20px;
  1455 + left: 0;
  1456 + -webkit-animation: line-spin-fade-loader 1.2s -0.84s infinite ease-in-out;
  1457 + animation: line-spin-fade-loader 1.2s -0.84s infinite ease-in-out; }
  1458 + .line-spin-fade-loader > div:nth-child(2) {
  1459 + top: 13.63636px;
  1460 + left: 13.63636px;
  1461 + -webkit-transform: rotate(-45deg);
  1462 + -ms-transform: rotate(-45deg);
  1463 + transform: rotate(-45deg);
  1464 + -webkit-animation: line-spin-fade-loader 1.2s -0.72s infinite ease-in-out;
  1465 + animation: line-spin-fade-loader 1.2s -0.72s infinite ease-in-out; }
  1466 + .line-spin-fade-loader > div:nth-child(3) {
  1467 + top: 0;
  1468 + left: 20px;
  1469 + -webkit-transform: rotate(90deg);
  1470 + -ms-transform: rotate(90deg);
  1471 + transform: rotate(90deg);
  1472 + -webkit-animation: line-spin-fade-loader 1.2s -0.6s infinite ease-in-out;
  1473 + animation: line-spin-fade-loader 1.2s -0.6s infinite ease-in-out; }
  1474 + .line-spin-fade-loader > div:nth-child(4) {
  1475 + top: -13.63636px;
  1476 + left: 13.63636px;
  1477 + -webkit-transform: rotate(45deg);
  1478 + -ms-transform: rotate(45deg);
  1479 + transform: rotate(45deg);
  1480 + -webkit-animation: line-spin-fade-loader 1.2s -0.48s infinite ease-in-out;
  1481 + animation: line-spin-fade-loader 1.2s -0.48s infinite ease-in-out; }
  1482 + .line-spin-fade-loader > div:nth-child(5) {
  1483 + top: -20px;
  1484 + left: 0;
  1485 + -webkit-animation: line-spin-fade-loader 1.2s -0.36s infinite ease-in-out;
  1486 + animation: line-spin-fade-loader 1.2s -0.36s infinite ease-in-out; }
  1487 + .line-spin-fade-loader > div:nth-child(6) {
  1488 + top: -13.63636px;
  1489 + left: -13.63636px;
  1490 + -webkit-transform: rotate(-45deg);
  1491 + -ms-transform: rotate(-45deg);
  1492 + transform: rotate(-45deg);
  1493 + -webkit-animation: line-spin-fade-loader 1.2s -0.24s infinite ease-in-out;
  1494 + animation: line-spin-fade-loader 1.2s -0.24s infinite ease-in-out; }
  1495 + .line-spin-fade-loader > div:nth-child(7) {
  1496 + top: 0;
  1497 + left: -20px;
  1498 + -webkit-transform: rotate(90deg);
  1499 + -ms-transform: rotate(90deg);
  1500 + transform: rotate(90deg);
  1501 + -webkit-animation: line-spin-fade-loader 1.2s -0.12s infinite ease-in-out;
  1502 + animation: line-spin-fade-loader 1.2s -0.12s infinite ease-in-out; }
  1503 + .line-spin-fade-loader > div:nth-child(8) {
  1504 + top: 13.63636px;
  1505 + left: -13.63636px;
  1506 + -webkit-transform: rotate(45deg);
  1507 + -ms-transform: rotate(45deg);
  1508 + transform: rotate(45deg);
  1509 + -webkit-animation: line-spin-fade-loader 1.2s 0s infinite ease-in-out;
  1510 + animation: line-spin-fade-loader 1.2s 0s infinite ease-in-out; }
  1511 + .line-spin-fade-loader > div {
  1512 + background-color: #fff;
  1513 + width: 4px;
  1514 + height: 35px;
  1515 + border-radius: 2px;
  1516 + margin: 2px;
  1517 + -webkit-animation-fill-mode: both;
  1518 + animation-fill-mode: both;
  1519 + position: absolute;
  1520 + width: 5px;
  1521 + height: 15px; }
  1522 +
  1523 +/**
  1524 + * Misc
  1525 + */
  1526 +@-webkit-keyframes triangle-skew-spin {
  1527 + 25% {
  1528 + -webkit-transform: perspective(100px) rotateX(180deg) rotateY(0);
  1529 + transform: perspective(100px) rotateX(180deg) rotateY(0); }
  1530 + 50% {
  1531 + -webkit-transform: perspective(100px) rotateX(180deg) rotateY(180deg);
  1532 + transform: perspective(100px) rotateX(180deg) rotateY(180deg); }
  1533 + 75% {
  1534 + -webkit-transform: perspective(100px) rotateX(0) rotateY(180deg);
  1535 + transform: perspective(100px) rotateX(0) rotateY(180deg); }
  1536 + 100% {
  1537 + -webkit-transform: perspective(100px) rotateX(0) rotateY(0);
  1538 + transform: perspective(100px) rotateX(0) rotateY(0); } }
  1539 +@keyframes triangle-skew-spin {
  1540 + 25% {
  1541 + -webkit-transform: perspective(100px) rotateX(180deg) rotateY(0);
  1542 + transform: perspective(100px) rotateX(180deg) rotateY(0); }
  1543 + 50% {
  1544 + -webkit-transform: perspective(100px) rotateX(180deg) rotateY(180deg);
  1545 + transform: perspective(100px) rotateX(180deg) rotateY(180deg); }
  1546 + 75% {
  1547 + -webkit-transform: perspective(100px) rotateX(0) rotateY(180deg);
  1548 + transform: perspective(100px) rotateX(0) rotateY(180deg); }
  1549 + 100% {
  1550 + -webkit-transform: perspective(100px) rotateX(0) rotateY(0);
  1551 + transform: perspective(100px) rotateX(0) rotateY(0); } }
  1552 +
  1553 +.triangle-skew-spin > div {
  1554 + -webkit-animation-fill-mode: both;
  1555 + animation-fill-mode: both;
  1556 + width: 0;
  1557 + height: 0;
  1558 + border-left: 20px solid transparent;
  1559 + border-right: 20px solid transparent;
  1560 + border-bottom: 20px solid #fff;
  1561 + -webkit-animation: triangle-skew-spin 3s 0s cubic-bezier(0.09, 0.57, 0.49, 0.9) infinite;
  1562 + animation: triangle-skew-spin 3s 0s cubic-bezier(0.09, 0.57, 0.49, 0.9) infinite; }
  1563 +
  1564 +@-webkit-keyframes square-spin {
  1565 + 25% {
  1566 + -webkit-transform: perspective(100px) rotateX(180deg) rotateY(0);
  1567 + transform: perspective(100px) rotateX(180deg) rotateY(0); }
  1568 + 50% {
  1569 + -webkit-transform: perspective(100px) rotateX(180deg) rotateY(180deg);
  1570 + transform: perspective(100px) rotateX(180deg) rotateY(180deg); }
  1571 + 75% {
  1572 + -webkit-transform: perspective(100px) rotateX(0) rotateY(180deg);
  1573 + transform: perspective(100px) rotateX(0) rotateY(180deg); }
  1574 + 100% {
  1575 + -webkit-transform: perspective(100px) rotateX(0) rotateY(0);
  1576 + transform: perspective(100px) rotateX(0) rotateY(0); } }
  1577 +
  1578 +@keyframes square-spin {
  1579 + 25% {
  1580 + -webkit-transform: perspective(100px) rotateX(180deg) rotateY(0);
  1581 + transform: perspective(100px) rotateX(180deg) rotateY(0); }
  1582 + 50% {
  1583 + -webkit-transform: perspective(100px) rotateX(180deg) rotateY(180deg);
  1584 + transform: perspective(100px) rotateX(180deg) rotateY(180deg); }
  1585 + 75% {
  1586 + -webkit-transform: perspective(100px) rotateX(0) rotateY(180deg);
  1587 + transform: perspective(100px) rotateX(0) rotateY(180deg); }
  1588 + 100% {
  1589 + -webkit-transform: perspective(100px) rotateX(0) rotateY(0);
  1590 + transform: perspective(100px) rotateX(0) rotateY(0); } }
  1591 +
  1592 +.square-spin > div {
  1593 + -webkit-animation-fill-mode: both;
  1594 + animation-fill-mode: both;
  1595 + width: 50px;
  1596 + height: 50px;
  1597 + background: #fff;
  1598 + border: 1px solid red;
  1599 + -webkit-animation: square-spin 3s 0s cubic-bezier(0.09, 0.57, 0.49, 0.9) infinite;
  1600 + animation: square-spin 3s 0s cubic-bezier(0.09, 0.57, 0.49, 0.9) infinite; }
  1601 +
  1602 +@-webkit-keyframes rotate_pacman_half_up {
  1603 + 0% {
  1604 + -webkit-transform: rotate(270deg);
  1605 + transform: rotate(270deg); }
  1606 + 50% {
  1607 + -webkit-transform: rotate(360deg);
  1608 + transform: rotate(360deg); }
  1609 + 100% {
  1610 + -webkit-transform: rotate(270deg);
  1611 + transform: rotate(270deg); } }
  1612 +
  1613 +@keyframes rotate_pacman_half_up {
  1614 + 0% {
  1615 + -webkit-transform: rotate(270deg);
  1616 + transform: rotate(270deg); }
  1617 + 50% {
  1618 + -webkit-transform: rotate(360deg);
  1619 + transform: rotate(360deg); }
  1620 + 100% {
  1621 + -webkit-transform: rotate(270deg);
  1622 + transform: rotate(270deg); } }
  1623 +
  1624 +@-webkit-keyframes rotate_pacman_half_down {
  1625 + 0% {
  1626 + -webkit-transform: rotate(90deg);
  1627 + transform: rotate(90deg); }
  1628 + 50% {
  1629 + -webkit-transform: rotate(0deg);
  1630 + transform: rotate(0deg); }
  1631 + 100% {
  1632 + -webkit-transform: rotate(90deg);
  1633 + transform: rotate(90deg); } }
  1634 +
  1635 +@keyframes rotate_pacman_half_down {
  1636 + 0% {
  1637 + -webkit-transform: rotate(90deg);
  1638 + transform: rotate(90deg); }
  1639 + 50% {
  1640 + -webkit-transform: rotate(0deg);
  1641 + transform: rotate(0deg); }
  1642 + 100% {
  1643 + -webkit-transform: rotate(90deg);
  1644 + transform: rotate(90deg); } }
  1645 +
  1646 +@-webkit-keyframes pacman-balls {
  1647 + 75% {
  1648 + opacity: 0.7; }
  1649 + 100% {
  1650 + -webkit-transform: translate(-100px, -6.25px);
  1651 + transform: translate(-100px, -6.25px); } }
  1652 +
  1653 +@keyframes pacman-balls {
  1654 + 75% {
  1655 + opacity: 0.7; }
  1656 + 100% {
  1657 + -webkit-transform: translate(-100px, -6.25px);
  1658 + transform: translate(-100px, -6.25px); } }
  1659 +
  1660 +.pacman {
  1661 + position: relative; }
  1662 + .pacman > div:nth-child(2) {
  1663 + -webkit-animation: pacman-balls 1s -0.99s infinite linear;
  1664 + animation: pacman-balls 1s -0.99s infinite linear; }
  1665 + .pacman > div:nth-child(3) {
  1666 + -webkit-animation: pacman-balls 1s -0.66s infinite linear;
  1667 + animation: pacman-balls 1s -0.66s infinite linear; }
  1668 + .pacman > div:nth-child(4) {
  1669 + -webkit-animation: pacman-balls 1s -0.33s infinite linear;
  1670 + animation: pacman-balls 1s -0.33s infinite linear; }
  1671 + .pacman > div:nth-child(5) {
  1672 + -webkit-animation: pacman-balls 1s 0s infinite linear;
  1673 + animation: pacman-balls 1s 0s infinite linear; }
  1674 + .pacman > div:first-of-type {
  1675 + width: 0px;
  1676 + height: 0px;
  1677 + border-right: 25px solid transparent;
  1678 + border-top: 25px solid #fff;
  1679 + border-left: 25px solid #fff;
  1680 + border-bottom: 25px solid #fff;
  1681 + border-radius: 25px;
  1682 + -webkit-animation: rotate_pacman_half_up 0.5s 0s infinite;
  1683 + animation: rotate_pacman_half_up 0.5s 0s infinite;
  1684 + position: relative;
  1685 + left: -30px; }
  1686 + .pacman > div:nth-child(2) {
  1687 + width: 0px;
  1688 + height: 0px;
  1689 + border-right: 25px solid transparent;
  1690 + border-top: 25px solid #fff;
  1691 + border-left: 25px solid #fff;
  1692 + border-bottom: 25px solid #fff;
  1693 + border-radius: 25px;
  1694 + -webkit-animation: rotate_pacman_half_down 0.5s 0s infinite;
  1695 + animation: rotate_pacman_half_down 0.5s 0s infinite;
  1696 + margin-top: -50px;
  1697 + position: relative;
  1698 + left: -30px; }
  1699 + .pacman > div:nth-child(3),
  1700 + .pacman > div:nth-child(4),
  1701 + .pacman > div:nth-child(5),
  1702 + .pacman > div:nth-child(6) {
  1703 + background-color: #fff;
  1704 + width: 15px;
  1705 + height: 15px;
  1706 + border-radius: 100%;
  1707 + margin: 2px;
  1708 + width: 10px;
  1709 + height: 10px;
  1710 + position: absolute;
  1711 + -webkit-transform: translate(0, -6.25px);
  1712 + -ms-transform: translate(0, -6.25px);
  1713 + transform: translate(0, -6.25px);
  1714 + top: 25px;
  1715 + left: 70px; }
  1716 +
  1717 +@-webkit-keyframes cube-transition {
  1718 + 25% {
  1719 + -webkit-transform: translateX(50px) scale(0.5) rotate(-90deg);
  1720 + transform: translateX(50px) scale(0.5) rotate(-90deg); }
  1721 + 50% {
  1722 + -webkit-transform: translate(50px, 50px) rotate(-180deg);
  1723 + transform: translate(50px, 50px) rotate(-180deg); }
  1724 + 75% {
  1725 + -webkit-transform: translateY(50px) scale(0.5) rotate(-270deg);
  1726 + transform: translateY(50px) scale(0.5) rotate(-270deg); }
  1727 + 100% {
  1728 + -webkit-transform: rotate(-360deg);
  1729 + transform: rotate(-360deg); } }
  1730 +
  1731 +@keyframes cube-transition {
  1732 + 25% {
  1733 + -webkit-transform: translateX(50px) scale(0.5) rotate(-90deg);
  1734 + transform: translateX(50px) scale(0.5) rotate(-90deg); }
  1735 + 50% {
  1736 + -webkit-transform: translate(50px, 50px) rotate(-180deg);
  1737 + transform: translate(50px, 50px) rotate(-180deg); }
  1738 + 75% {
  1739 + -webkit-transform: translateY(50px) scale(0.5) rotate(-270deg);
  1740 + transform: translateY(50px) scale(0.5) rotate(-270deg); }
  1741 + 100% {
  1742 + -webkit-transform: rotate(-360deg);
  1743 + transform: rotate(-360deg); } }
  1744 +
  1745 +.cube-transition {
  1746 + position: relative;
  1747 + -webkit-transform: translate(-25px, -25px);
  1748 + -ms-transform: translate(-25px, -25px);
  1749 + transform: translate(-25px, -25px); }
  1750 + .cube-transition > div {
  1751 + -webkit-animation-fill-mode: both;
  1752 + animation-fill-mode: both;
  1753 + width: 10px;
  1754 + height: 10px;
  1755 + position: absolute;
  1756 + top: -5px;
  1757 + left: -5px;
  1758 + background-color: #fff;
  1759 + -webkit-animation: cube-transition 1.6s 0s infinite ease-in-out;
  1760 + animation: cube-transition 1.6s 0s infinite ease-in-out; }
  1761 + .cube-transition > div:last-child {
  1762 + -webkit-animation-delay: -0.8s;
  1763 + animation-delay: -0.8s; }
  1764 +
  1765 +@-webkit-keyframes spin-rotate {
  1766 + 0% {
  1767 + -webkit-transform: rotate(0deg);
  1768 + transform: rotate(0deg); }
  1769 + 50% {
  1770 + -webkit-transform: rotate(180deg);
  1771 + transform: rotate(180deg); }
  1772 + 100% {
  1773 + -webkit-transform: rotate(360deg);
  1774 + transform: rotate(360deg); } }
  1775 +
  1776 +@keyframes spin-rotate {
  1777 + 0% {
  1778 + -webkit-transform: rotate(0deg);
  1779 + transform: rotate(0deg); }
  1780 + 50% {
  1781 + -webkit-transform: rotate(180deg);
  1782 + transform: rotate(180deg); }
  1783 + 100% {
  1784 + -webkit-transform: rotate(360deg);
  1785 + transform: rotate(360deg); } }
  1786 +
  1787 +.semi-circle-spin {
  1788 + position: relative;
  1789 + width: 35px;
  1790 + height: 35px;
  1791 + overflow: hidden; }
  1792 + .semi-circle-spin > div {
  1793 + position: absolute;
  1794 + border-width: 0px;
  1795 + border-radius: 100%;
  1796 + -webkit-animation: spin-rotate 0.6s 0s infinite linear;
  1797 + animation: spin-rotate 0.6s 0s infinite linear;
  1798 + background-image: -webkit-linear-gradient(transparent 0%, transparent 70%, #fff 30%, #fff 100%);
  1799 + background-image: linear-gradient(transparent 0%, transparent 70%, #fff 30%, #fff 100%);
  1800 + width: 100%;
  1801 + height: 100%; }
  1802 +
  1803 +@-webkit-keyframes bar-progress {
  1804 + 0% {
  1805 + -webkit-transform: scaleY(20%);
  1806 + transform: scaleY(20%);
  1807 + opacity: 1; }
  1808 + 25% {
  1809 + -webkit-transform: translateX(6%) scaleY(10%);
  1810 + transform: translateX(6%) scaleY(10%);
  1811 + opacity: 0.7; }
  1812 + 50% {
  1813 + -webkit-transform: translateX(20%) scaleY(20%);
  1814 + transform: translateX(20%) scaleY(20%);
  1815 + opacity: 1; }
  1816 + 75% {
  1817 + -webkit-transform: translateX(6%) scaleY(10%);
  1818 + transform: translateX(6%) scaleY(10%);
  1819 + opacity: 0.7; }
  1820 + 100% {
  1821 + -webkit-transform: scaleY(20%);
  1822 + transform: scaleY(20%);
  1823 + opacity: 1; } }
  1824 +
  1825 +@keyframes bar-progress {
  1826 + 0% {
  1827 + -webkit-transform: scaleY(20%);
  1828 + transform: scaleY(20%);
  1829 + opacity: 1; }
  1830 + 25% {
  1831 + -webkit-transform: translateX(6%) scaleY(10%);
  1832 + transform: translateX(6%) scaleY(10%);
  1833 + opacity: 0.7; }
  1834 + 50% {
  1835 + -webkit-transform: translateX(20%) scaleY(20%);
  1836 + transform: translateX(20%) scaleY(20%);
  1837 + opacity: 1; }
  1838 + 75% {
  1839 + -webkit-transform: translateX(6%) scaleY(10%);
  1840 + transform: translateX(6%) scaleY(10%);
  1841 + opacity: 0.7; }
  1842 + 100% {
  1843 + -webkit-transform: scaleY(20%);
  1844 + transform: scaleY(20%);
  1845 + opacity: 1; } }
  1846 +
  1847 +.bar-progress {
  1848 + width: 30%;
  1849 + height: 12px; }
  1850 + .bar-progress > div {
  1851 + position: relative;
  1852 + width: 20%;
  1853 + height: 12px;
  1854 + border-radius: 10px;
  1855 + background-color: #fff;
  1856 + -webkit-animation: bar-progress 3s cubic-bezier(0.57, 0.1, 0.44, 0.93) infinite;
  1857 + animation: bar-progress 3s cubic-bezier(0.57, 0.1, 0.44, 0.93) infinite;
  1858 + opacity: 1; }
  1859 +
  1860 +@-webkit-keyframes bar-swing {
  1861 + 0% {
  1862 + left: 0; }
  1863 + 50% {
  1864 + left: 70%; }
  1865 + 100% {
  1866 + left: 0; } }
  1867 +
  1868 +@keyframes bar-swing {
  1869 + 0% {
  1870 + left: 0; }
  1871 + 50% {
  1872 + left: 70%; }
  1873 + 100% {
  1874 + left: 0; } }
  1875 +
  1876 +.bar-swing {
  1877 + width: 30%;
  1878 + height: 8px; }
  1879 + .bar-swing > div {
  1880 + position: relative;
  1881 + width: 30%;
  1882 + height: 8px;
  1883 + border-radius: 10px;
  1884 + background-color: #fff;
  1885 + -webkit-animation: bar-swing 1.5s infinite;
  1886 + animation: bar-swing 1.5s infinite; }
  1887 +
  1888 +@-webkit-keyframes bar-swing-container {
  1889 + 0% {
  1890 + left: 0;
  1891 + -webkit-transform: translateX(0);
  1892 + transform: translateX(0); }
  1893 + 50% {
  1894 + left: 70%;
  1895 + -webkit-transform: translateX(-4px);
  1896 + transform: translateX(-4px); }
  1897 + 100% {
  1898 + left: 0;
  1899 + -webkit-transform: translateX(0);
  1900 + transform: translateX(0); } }
  1901 +
  1902 +@keyframes bar-swing-container {
  1903 + 0% {
  1904 + left: 0;
  1905 + -webkit-transform: translateX(0);
  1906 + transform: translateX(0); }
  1907 + 50% {
  1908 + left: 70%;
  1909 + -webkit-transform: translateX(-4px);
  1910 + transform: translateX(-4px); }
  1911 + 100% {
  1912 + left: 0;
  1913 + -webkit-transform: translateX(0);
  1914 + transform: translateX(0); } }
  1915 +
  1916 +.bar-swing-container {
  1917 + width: 20%;
  1918 + height: 8px;
  1919 + position: relative; }
  1920 + .bar-swing-container div:nth-child(1) {
  1921 + position: absolute;
  1922 + width: 100%;
  1923 + background-color: rgba(255, 255, 255, 0.2);
  1924 + height: 12px;
  1925 + border-radius: 10px; }
  1926 + .bar-swing-container div:nth-child(2) {
  1927 + position: absolute;
  1928 + width: 30%;
  1929 + height: 8px;
  1930 + border-radius: 10px;
  1931 + background-color: #fff;
  1932 + -webkit-animation: bar-swing-container 2s cubic-bezier(0.91, 0.35, 0.12, 0.6) infinite;
  1933 + animation: bar-swing-container 2s cubic-bezier(0.91, 0.35, 0.12, 0.6) infinite;
  1934 + margin: 2px 2px 0; }
\ No newline at end of file
... ...
  1 +.bootstrap-tagsinput {
  2 + background-color: #fff;
  3 + border: 1px solid #ccc;
  4 + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
  5 + display: inline-block;
  6 + padding: 4px 6px;
  7 + color: #555;
  8 + vertical-align: middle;
  9 + border-radius: 4px;
  10 + max-width: 100%;
  11 + line-height: 22px;
  12 + cursor: text;
  13 +}
  14 +.bootstrap-tagsinput input {
  15 + border: none;
  16 + box-shadow: none;
  17 + outline: none;
  18 + background-color: transparent;
  19 + padding: 0 6px;
  20 + margin: 0;
  21 + width: auto;
  22 + max-width: inherit;
  23 +}
  24 +.bootstrap-tagsinput.form-control input::-moz-placeholder {
  25 + color: #777;
  26 + opacity: 1;
  27 +}
  28 +.bootstrap-tagsinput.form-control input:-ms-input-placeholder {
  29 + color: #777;
  30 +}
  31 +.bootstrap-tagsinput.form-control input::-webkit-input-placeholder {
  32 + color: #777;
  33 +}
  34 +.bootstrap-tagsinput input:focus {
  35 + border: none;
  36 + box-shadow: none;
  37 +}
  38 +.bootstrap-tagsinput .tag {
  39 + margin-right: 2px;
  40 + color: white;
  41 +}
  42 +.bootstrap-tagsinput .tag [data-role="remove"] {
  43 + margin-left: 8px;
  44 + cursor: pointer;
  45 +}
  46 +.bootstrap-tagsinput .tag [data-role="remove"]:after {
  47 + content: "x";
  48 + padding: 0px 2px;
  49 +}
  50 +.bootstrap-tagsinput .tag [data-role="remove"]:hover {
  51 + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
  52 +}
  53 +.bootstrap-tagsinput .tag [data-role="remove"]:hover:active {
  54 + box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
  55 +}
... ...
... ... @@ -5,12 +5,28 @@ module Kanjai
5 5 @s3_direct_post = S3_BUCKET.presigned_post(key: "#{Image.get_image_file_path}${filename}", success_action_status: '201', acl: 'public-read')
6 6 end
7 7
  8 + def list
  9 + collection = Kanjai::Image.all
  10 + if params[:tags] && params[:tags].count > 0 && !params[:tags].include?('all')
  11 + collection = collection.tagged_with(params[:tags], :any => true)
  12 + end
  13 +
  14 + render partial: 'kanjai/admin/images/gallery_exist_images', locals: {collection: collection}
  15 + end
8 16
9 17 def update_gallery
10 18 params[:gallery_image] ||= {}
11   - params[:gallery_image].each do |key, url|
  19 + params[:gallery_image].each do |key, data|
  20 +
  21 + obj = S3_BUCKET.object(URI.parse(data['file']).path[1..-1])
  22 +
  23 +
12 24 Image.create({
13   - image_link: url
  25 + title: data['name'],
  26 + file_type: data['type'],
  27 + file_size: obj.content_length,
  28 + image_link: data['file'],
  29 + tag_list: data['tags']
14 30 })
15 31
16 32 end
... ...
1 1 module Kanjai
2 2 class Admin::PageTemplatesController < AdminController
3 3
4   - before_action :set_s3_direct_post, only: [:edit, :update]
  4 + before_action :set_s3_direct_post, only: [:new, :update, :edit, :update]
5 5
6   - after_action :unzip_content, only: [:update]
  6 + after_action :unzip_content, only: [:create, :update]
7 7
8 8 def index
9 9 @collection = PageTemplate.order(:title)
... ... @@ -11,16 +11,15 @@ module Kanjai
11 11
12 12 def new
13 13 @page_template = PageTemplate.new
14   - render :layout => false
15 14 end
16 15
17 16 def create
18 17 @page_template = PageTemplate.new(permitted_params[:page_template])
19   -
  18 +
20 19 if @page_template.save
21   - render :partial => 'kanjai/admin/page_templates/create/success'
  20 + redirect_to admin_page_templates_url
22 21 else
23   - render :partial => 'kanjai/admin/page_templates/create/error'
  22 + render action: :new
24 23 end
25 24 end
26 25
... ... @@ -97,8 +96,7 @@ module Kanjai
97 96 end
98 97
99 98 def set_s3_direct_post
100   - page_template = PageTemplate.find(params[:id])
101   - @s3_direct_post = S3_BUCKET.presigned_post(key: "#{page_template.get_file_path}${filename}", success_action_status: '201', acl: 'private')
  99 + @s3_direct_post = S3_BUCKET.presigned_post(key: "tmp/templates/${filename}", success_action_status: '201', acl: 'private')
102 100 end
103 101
104 102 end
... ...
  1 +module Kanjai
  2 + class Admin::TagsController < AdminController
  3 + def index
  4 + render json: ActsAsTaggableOn::Tag.order(:name).pluck(:name)
  5 + end
  6 + end
  7 +end
\ No newline at end of file
... ...
1 1 module Kanjai
2 2 class Image < ActiveRecord::Base
  3 + acts_as_taggable
  4 +
3 5 belongs_to :object, polymorphic: true, optional: true
4 6
5 7 # has_attached_file :image,
... ...
... ... @@ -20,6 +20,8 @@ module Kanjai
20 20
21 21 default_scope { order('title') }
22 22
  23 + after_save :move_file
  24 +
23 25 def get_file_path
24 26 "templates/#{self.id}/"
25 27 end
... ... @@ -174,7 +176,6 @@ module Kanjai
174 176 uri = URI.parse(url)
175 177 file_name = File.basename(uri.path)
176 178 self.original_file_name = file_name
177   -
178 179 end
179 180
180 181 def file_expiring_url
... ... @@ -188,6 +189,20 @@ module Kanjai
188 189 url
189 190 end
190 191
  192 + private
  193 +
  194 + def move_file
  195 + if attachment_file_name.present? && attachment_file_name.include?('tmp/templates')
  196 + obj_path = URI.parse(attachment_file_name).path
  197 +
  198 + file_name = File.basename(obj_path)
  199 +
  200 + s3 = Aws::S3::Client.new(region: ENV['S3_REGION'])
  201 + s3.copy_object(bucket: ENV['S3_BUCKET'], copy_source: "/#{ENV['S3_BUCKET']}#{obj_path}", key: "#{get_file_path}#{file_name}")
  202 + self.update_column(:attachment_file_name, "#{get_file_path}#{file_name}")
  203 + end
  204 + end
  205 +
191 206
192 207 end
193 208 end
\ No newline at end of file
... ...
1   -<% if Kanjai::Image.all.count == 0 %>
2   - <p class="empty-block">Image not exist</p>
3   -<% else %>
4   - <div class="gallery-list">
5   - <% Kanjai::Image.all.each do |item| %>
6   - <%= render :partial => 'preview', :locals => {item: item} %>
7   - <% end %>
  1 +<div class="card-columns">
  2 + <% collection.each do |item| %>
  3 + <div class="card mb-4" id="gallery_image_<%= item.id %>" >
  4 + <%= image_tag item.image_link, class: 'card-img-top img-fluid', alt: '' %>
  5 + <div class="card-body">
  6 + <div class="content">
  7 + <h4 class="card-title"><%= item.title %></h4>
  8 + <p class="card-text">Size: <%= number_to_human_size(item.file_size) %></p>
  9 + <p class="card-text">Format: <%= item.file_type %></p>
  10 + </div>
  11 + <div class="action">
  12 + <div class="dropdown dropleft without-icon">
  13 + <button class="btn btn-secondary dropdown-toggle dropdown-toggle-nocaret" type="button" data-toggle="dropdown" aria-expanded="false">
  14 + <span class="dropdown-text"><span class="icon icon-options-vertical"></span></span>
  15 + </button>
  16 + <ul class="dropdown-menu" style="padding-left:0;">
  17 + <li class="dropdown-item"><%= link_to t('action.edit'), edit_admin_image_url(item), class: 'dropdown-item' %></li>
  18 + <li class="dropdown-item"><%= link_to t('action.delete'), delete_gallery_image_admin_image_path(item), remote: true, :class => 'dropdown-item' %></li>
  19 + </ul>
  20 + </div>
  21 + </div>
  22 + </div>
8 23 </div>
9   -<% end %>
\ No newline at end of file
  24 + <% end %>
  25 +
  26 +
  27 +</div>
... ...
  1 +<div class="card card-default new-image-wrapper">
  2 + <div class="card-body">
  3 + <div class="text-right">
  4 + <%= link_to '#', class: 'remove' do %>
  5 + <i class="fa fa-times"></i>
  6 + <% end %>
  7 + </div>
  8 + <div class="row">
  9 + <div class="col-md-8">
  10 + <fieldset>
  11 + <div class="form-group row">
  12 + <label class="col-md-2 col-form-label">Name</label>
  13 + <div class="col-md-10">
  14 + <input class="form-control" type="text" name="{name}name" >
  15 + <input class="form-control file-type" type="hidden" name="{name}type" >
  16 + </div>
  17 + </div>
  18 + </fieldset>
  19 +
  20 + <fieldset>
  21 + <div class="form-group row">
  22 + <label class="col-md-2 col-form-label">Tags</label>
  23 + <div class="col-md-10">
  24 + <input class="form-control" type="text" name="{name}tags" data-role="tagsinput" >
  25 + </div>
  26 + </div>
  27 + </fieldset>
  28 +
  29 + </div>
  30 + <div class="col-md-4">
  31 + <div class='fileupload-preview'></div>
  32 + </div>
  33 + </div>
  34 + </div>
  35 +</div>
\ No newline at end of file
... ...
1   -<div class="container">
2   -
3   - <h3><%= t('admin.gallery.title') %></h3>
4   -
5   - <div class="row">
6   - <div class="col-md-12 gallery-block">
  1 +<div class="content-wrapper">
  2 + <div class="container">
7 3
8 4 <div class="drop-down-upload">
9 5 <div style="padding:10px;">
... ... @@ -15,26 +11,46 @@
15 11 </div>
16 12
17 13 <div id="gallery_form">
18   - <form action="<%= update_gallery_admin_images_url %>" class="ajax-file-upload-form">
19   - <input type="submit" value="Save" class="btn btn-default not-visible" />
20   - <div id="new_images">
21   -
22   - </div>
23   - </form>
24   -
25   - <div class="clearfix"></div>
  14 + <form action="<%= update_gallery_admin_images_url %>" class="ajax-file-upload-form">
  15 + <div id="new_images">
26 16
27   - <h2>Exist Image</h2>
28   -
29   - <div id="exist_images">
30   - <%= render partial: 'kanjai/admin/images/gallery_exist_images' %>
31 17 </div>
  18 + <div class="text-center">
  19 + <%= link_to 'Add More', '#', class: 'btn btn-primary add-new-field not-visible', data: {template: render(partial: 'kanjai/admin/images/image_field')} %>
  20 + </div>
  21 + <div class="text-right">
  22 + <input type="submit" value="Upload" class="btn btn-primary not-visible" />
  23 + </div>
  24 + </form>
32 25 </div>
33 26
34   - </div>
35   -
  27 + <div class="mt-20 image-list" data-url='<%= list_admin_images_url %>'>
  28 + <div class="filter">
  29 + <div class="btn-group-toggle">
  30 + <label data-value='all' class="btn btn-primary active">All</label>
  31 + <% ActsAsTaggableOn::Tag.most_used.each do |tag| %>
  32 + <label data-value='<%= tag.name %>' class="btn btn-primary"><%= tag.name %></label>
  33 + <% end %>
  34 + </div>
  35 + </div>
  36 + <div class="loader-demo">
  37 + <div class="ball-grid-pulse">
  38 + <div></div>
  39 + <div></div>
  40 + <div></div>
  41 + <div></div>
  42 + <div></div>
  43 + <div></div>
  44 + <div></div>
  45 + <div></div>
  46 + <div></div>
  47 + </div>
  48 + </div>
  49 + <div class="exist-image-list mt-20">
36 50
37   - </div>
  51 + </div>
  52 + </div>
  53 + </div>
  54 +</div>
38 55
39 56
40   -</div>
\ No newline at end of file
... ...
  1 +$(window).trigger('images:update');
1 2 $('#gallery_form form #new_images').html('');
2 3 $('#gallery_form form input:submit').addClass('not-visible');
3   -
4   -$('#exist_images').html('<%=j render partial: 'kanjai/admin/images/gallery_exist_images' %>');
\ No newline at end of file
... ...
... ... @@ -35,8 +35,8 @@
35 35 <span class="dropdown-text"><span class="icon icon-options-vertical"></span></span>
36 36 </button>
37 37 <ul class="dropdown-menu">
38   - <li class="dropdown-item"><%= link_to t('edit_action'), edit_admin_page_lang_url(item), class: 'dropdown-item' %></li>
39   - <li class="dropdown-item"><%= link_to t('delete_action'), admin_page_lang_url(item), :class => 'delete-row-item dropdown-item' %></li>
  38 + <li class="dropdown-item"><%= link_to t('action.edit'), edit_admin_page_lang_url(item), class: 'dropdown-item' %></li>
  39 + <li class="dropdown-item"><%= link_to t('action.delete'), admin_page_lang_url(item), :class => 'delete-row-item dropdown-item' %></li>
40 40 </ul>
41 41 </div>
42 42 </td>
... ...
  1 +<div class="card-body">
  2 + <div class="form-group">
  3 + <%= f.label :title, Kanjai::PageTemplate.human_attribute_name(:title) + ' *', class: 'col-form-label' %>
  4 + <%= f.text_field :title, required: true, class: "form-control #{@page_template.errors.include?(:title) ? 'parsley-error' : ''} " %>
  5 + <%= error_messages(@page_template, :title) %>
  6 + </div>
  7 +
  8 + <div class="form-group">
  9 + <%= f.label :notice, Kanjai::PageTemplate.human_attribute_name(:notice), class: 'col-form-label' %>
  10 + <%= f.text_area :notice, class: "form-control #{@page_template.errors.include?(:notice) ? 'parsley-error' : ''} " %>
  11 + <%= error_messages(@page_template, :notice) %>
  12 + </div>
  13 +
  14 +
  15 + <fieldset>
  16 + <div class="form-group row">
  17 + <%= f.label :attachment_file_name, Kanjai::PageTemplate.human_attribute_name(:attachment), :class => "col-md-2 col-form-label" %>
  18 + <div class="col-md-10">
  19 + <%= f.file_field :attachment_file_name, :class => "form-control filestyle", 'data-url' => @s3_direct_post.url, 'data-form-data' => @s3_direct_post.fields.to_json, 'data-host' => URI.parse(@s3_direct_post.url).host , 'data-type' => 'zip', 'data-classbutton' => 'btn btn-secondary', 'data-classinput' => "form-control inline", 'data-icon' => "<span class='fa fa-upload mr-2'></span>" %>
  20 + <% if @url %>
  21 + <div>
  22 + <%= link_to @page_template.original_file_name, @url, target: '_blank' %>
  23 + </div>
  24 + <% end %>
  25 +
  26 + </div>
  27 + </div>
  28 + </fieldset>
  29 +
  30 + <div class="card-footer mt-20">
  31 + <div class="clearfix">
  32 + <div class="float-right">
  33 + <%= link_to t('actions.cancel'), admin_page_templates_url, class: 'btn btn-secondary' %>
  34 + <button class="btn btn-primary" type="submit"><%= t('actions.save') %></button>
  35 + </div>
  36 + </div>
  37 + </div>
  38 +
  39 +</div>
\ No newline at end of file
... ...
1   -<%= fields_for object do |form| %>
2   - <div class="form-group <%= object.errors.include?(:title) ? 'has-error' : '' %>">
3   - <%= form.label :title, t('activerecord.attributes.template.title') + '*', :class => "control-label" %>
4   - <%= form.text_field :title, :class => "form-control" %>
5   - <%= error_messages(object, :title) %>
6   - </div>
7   -<% end %>
\ No newline at end of file
1   -$('#create_template_form_content').html('<%=j render :partial => 'new_form', :locals => {object: resource} %>');
\ No newline at end of file
1   -document.location.href = '<%= edit_admin_page_template_url(@page_template) %>';
\ No newline at end of file
1   -<div class="container">
2   -
3   - <h3><%= t('admin.templates.edit_template') %></h3>
4   -
5   -
6   -
7   - <%= render :partial => 'kanjai/shared/error_messages', :locals => {:target => @page_template} %>
8   -
9   - <%= form_for(@page_template, :url => admin_page_template_url(@page_template), :html => {:class => "form-horizontal ajax-file-upload-form simple_submit"}) do |form| %>
10   -
11   - <div class="form-group <%= @page_template.errors.include?(:title) ? 'has-error' : '' %>">
12   - <%= form.label :title, t('activerecord.attributes.template.title') + '*', :class => "col-sm-2 control-label" %>
13   - <div class="col-sm-10">
14   - <%= form.text_field :title, :class => "form-control" %>
15   - <%= error_messages(@page_template, :title) %>
16   - </div>
17   - </div>
18   -
19   - <div class="form-group <%= @page_template.errors.include?(:attachment) ? 'has-error' : '' %>">
20   - <%= form.label :attachment_file_name, t('activerecord.attributes.template.attachment'), :class => "col-sm-2 control-label" %>
21   - <div class="col-sm-10">
22   - <%= form.file_field :attachment_file_name, :class => "", 'data-url' => @s3_direct_post.url, 'data-form-data' => @s3_direct_post.fields.to_json, 'data-host' => URI.parse(@s3_direct_post.url).host , 'data-type' => 'zip' %>
23   - <% if @url %>
24   - <div>
25   - <%= link_to @page_template.original_file_name, @url, target: '_blank' %>
26   - </div>
27   - <% end %>
28   - <%= error_messages(@page_template, :attachment) %>
29   - </div>
30   - </div>
31   -
32   - <%= render :partial => 'kanjai/shared/edit_resource_links', locals: {collection_url: admin_page_templates_url} %>
33   - <% end %>
34   -
35   -
36   -
37   -
  1 +<div class="content-wrapper">
  2 + <div class="row">
  3 + <div class="col-xl-12">
  4 +
  5 + <%= form_for @page_template, url: admin_page_template_url(@page_template), html: {class: 'form-horizontal ajax-file-upload-form simple_submit'} do |f| %>
  6 + <div class="card card-default">
  7 + <div class="card-header">
  8 + <div class="card-title"><%= t('admin.templates.edit') %></div>
  9 + </div>
  10 + <%= render partial: 'form', locals: {f: f} %>
  11 + </div>
  12 + <% end %>
  13 +
  14 + </div>
  15 + </div>
38 16 </div>
... ...
1   -<div class="container">
2   - <h1><%= t('admin.templates.page_title') %></h1>
  1 +<div class="content-wrapper">
  2 + <div class="row">
  3 + <div class="col-xl-12">
  4 + <!-- START card-->
  5 + <div class="card card-default">
  6 + <div class="card-header">
  7 + <div class="row">
  8 + <div class="col-md-8">
  9 + <%= t('admin.page_langs.title') %>
  10 + </div>
  11 + <div class="col-md-4 text-right">
  12 + <%= link_to I18n.t('admin.templates.create'), new_admin_page_template_url, class: 'btn btn-primary' %>
  13 + </div>
  14 + </div>
  15 + </div>
  16 + <div class="card-body">
  17 + <!-- START table-responsive-->
  18 + <div class="table-responsive">
  19 + <table class="table">
  20 + <thead>
  21 + <tr>
  22 + <th><%= Kanjai::PageTemplate.human_attribute_name(:title) %></th>
  23 + <th><%= Kanjai::PageTemplate.human_attribute_name(:unzip) %></th>
  24 + <th><%= Kanjai::PageTemplate.human_attribute_name(:updated_at) %></th>
  25 + <th><%= Kanjai::PageTemplate.human_attribute_name(:notice) %></th>
  26 + <th width="50px"></th>
  27 + </tr>
  28 + </thead>
  29 + <tbody>
  30 + <% @collection.each do |item| %>
  31 + <tr id='<%= dom_id(item) %>'>
  32 + <td><%= item.title %></td>
  33 + <td><%= (item.unzip ? 'unzip' : 'zip') %></td>
  34 + <td><%= I18n.l(item.updated_at) %></td>
  35 + <td><%= item.notice %></td>
  36 + <td>
  37 + <div class="dropdown">
  38 + <button class="btn btn-secondary dropdown-toggle dropdown-toggle-nocaret" type="button" data-toggle="dropdown" aria-expanded="false">
  39 + <span class="dropdown-text"><span class="icon icon-options-vertical"></span></span>
  40 + </button>
  41 + <ul class="dropdown-menu">
  42 + <li class="dropdown-item"><%= link_to t('action.edit'), edit_admin_page_template_url(item), class: 'dropdown-item' %></li>
  43 + <li class="dropdown-item"><%= link_to t('action.delete'), admin_page_template_url(item), :class => 'delete-row-item dropdown-item' %></li>
  44 + <% Kanjai::PageLang.all.each do |lang| %>
  45 + <li class="dropdown-item"><%= link_to "Static Element #{lang.code}", marker_admin_page_template_url(item, :lang => lang.code), class: 'dropdown-item' %></li>
  46 + <% end %>
  47 + </ul>
  48 + </div>
  49 + </td>
  50 + </tr>
  51 + <% end %>
3 52
4   - <div class="pull-right">
5   - <%= link_to t('admin.templates.add_new'), new_admin_page_template_url, remote: true, class: 'btn btn-success link-add-new-template' %>
  53 + </tbody>
  54 + </table>
  55 + </div><!-- END table-responsive-->
  56 + </div>
  57 + </div><!-- END card-->
  58 + </div>
6 59 </div>
  60 +</div>
7 61
8   - <% if @collection.count == 0 %>
9   - <p class="text-center"><%= t('admin.templates.empty_text') %></p>
10   - <% else %>
11   - <table class="table">
12   - <thead>
13   - <tr>
14   - <th><%= t('activerecord.attributes.template.title') %></th>
15   - <th><%= t('activerecord.attributes.template.unzip') %></th>
16   - <th></th>
17   - </tr>
18   - </thead>
19   - <tbody>
20   - <% @collection.each do |item| %>
21   - <tr>
22   - <td><%= item.title %></td>
23   - <td>
24   - <%= (item.unzip ? 'unzip' : 'zip') %>
25   - </td>
26   - <td>
27   - <%= link_to 'Edit', edit_admin_page_template_url(item) %> |
28   - <% Kanjai::PageLang.all.each do |lang| %>
29   - <%= link_to "Static Element #{lang.code}", marker_admin_page_template_url(item, :lang => lang.code) %> |
30   - <% end %>
31   - <%= link_to 'Delete', admin_page_template_url(item), :class => 'delete-row-item' %>
32   - </td>
33   - </tr>
34   - <% end %>
35   - </tbody>
36   - </table>
37   -
38   - <% end %>
39   -
40   -</div>
\ No newline at end of file
... ...
1   -<%= form_for(@page_template, :url => admin_page_templates_path, remote: true) do |form| %>
  1 +<div class="content-wrapper">
  2 + <div class="row">
  3 + <div class="col-xl-12">
2 4
3   - <div id="create_template_form_content">
4   - <%= render :partial => 'new_form', :locals => {object: @page_template} %>
5   - </div>
  5 + <%= form_for @page_template, url: admin_page_templates_path, html: {class: 'form-horizontal ajax-file-upload-form simple_submit'} do |f| %>
  6 + <div class="card card-default">
  7 + <div class="card-header">
  8 + <div class="card-title"><%= t('admin.templates.create') %></div>
  9 + </div>
  10 +
  11 + <%= render partial: 'form', locals: {f: f} %>
6 12
  13 + </div>
  14 + <% end %>
7 15
8   - <div class="text-center popover-action">
9   - <a href="javascript:void(0);" class="send-form"><%= t('actions.create') %></a> |
10   - <a href="javascript:void(0);" class="cancel-send"><%= t('actions.cancel') %></a>
11 16 </div>
12   -<% end %>
\ No newline at end of file
  17 + </div>
  18 +</div>
\ No newline at end of file
... ...
... ... @@ -124,9 +124,9 @@ en:
124 124 edit: "Edit lang"
125 125 templates:
126 126 page_title: "Templates"
127   - add_new: "Add Template"
128 127 empty_text: "You don't have template"
129 128 edit_template: "Edit Template"
  129 + create: "Create Template"
130 130 gallery:
131 131 title: "Gallery"
132 132
... ...
... ... @@ -20,6 +20,7 @@ Kanjai::Engine.routes.draw do
20 20 post 'page_contents/add_item' => "page_contents#add_item"
21 21 post 'page_contents/delete_item' => "page_contents#delete_item"
22 22 post 'page_contents/sorting' => "page_contents#sorting"
  23 + get 'tags' => 'tags#index'
23 24
24 25 resources :admin_users
25 26
... ... @@ -52,11 +53,12 @@ Kanjai::Engine.routes.draw do
52 53 post :update_marker, on: :member
53 54 end
54 55
55   - resources :images, only: [:index] do
  56 + resources :images, only: [:index, :edit, :update] do
56 57 post :update_gallery, on: :collection
57 58 get :delete_gallery_image, on: :member
58 59
59 60 post :get_gallery, on: :collection
  61 + post :list, on: :collection
60 62 end
61 63
62 64 end
... ...
  1 +class AddNoticeToTemplate < ActiveRecord::Migration[5.2]
  2 + def change
  3 + add_column :kanjai_templates, :notice, :string
  4 + end
  5 +end
... ...
  1 +class AddSizeAndTypeToImage < ActiveRecord::Migration[5.2]
  2 + def change
  3 + add_column :kanjai_images, :file_type, :string
  4 + add_column :kanjai_images, :file_size, :bigint
  5 + end
  6 +end
... ...
  1 +# This migration comes from acts_as_taggable_on_engine (originally 1)
  2 +if ActiveRecord.gem_version >= Gem::Version.new('5.0')
  3 + class ActsAsTaggableOnMigration < ActiveRecord::Migration[4.2]; end
  4 +else
  5 + class ActsAsTaggableOnMigration < ActiveRecord::Migration; end
  6 +end
  7 +ActsAsTaggableOnMigration.class_eval do
  8 + def self.up
  9 + create_table ActsAsTaggableOn.tags_table do |t|
  10 + t.string :name
  11 + t.timestamps
  12 + end
  13 +
  14 + create_table ActsAsTaggableOn.taggings_table do |t|
  15 + t.references :tag, foreign_key: { to_table: ActsAsTaggableOn.tags_table }
  16 +
  17 + # You should make sure that the column created is
  18 + # long enough to store the required class names.
  19 + t.references :taggable, polymorphic: true
  20 + t.references :tagger, polymorphic: true
  21 +
  22 + # Limit is created to prevent MySQL error on index
  23 + # length for MyISAM table type: http://bit.ly/vgW2Ql
  24 + t.string :context, limit: 128
  25 +
  26 + t.datetime :created_at
  27 + end
  28 +
  29 + add_index ActsAsTaggableOn.taggings_table, :tag_id
  30 + add_index ActsAsTaggableOn.taggings_table, [:taggable_id, :taggable_type, :context], name: 'taggings_taggable_context_idx'
  31 + end
  32 +
  33 + def self.down
  34 + drop_table ActsAsTaggableOn.taggings_table
  35 + drop_table ActsAsTaggableOn.tags_table
  36 + end
  37 +end
... ...
  1 +# This migration comes from acts_as_taggable_on_engine (originally 2)
  2 +if ActiveRecord.gem_version >= Gem::Version.new('5.0')
  3 + class AddMissingUniqueIndices < ActiveRecord::Migration[4.2]; end
  4 +else
  5 + class AddMissingUniqueIndices < ActiveRecord::Migration; end
  6 +end
  7 +AddMissingUniqueIndices.class_eval do
  8 + def self.up
  9 + add_index ActsAsTaggableOn.tags_table, :name, unique: true
  10 +
  11 + remove_index ActsAsTaggableOn.taggings_table, :tag_id if index_exists?(ActsAsTaggableOn.taggings_table, :tag_id)
  12 + remove_index ActsAsTaggableOn.taggings_table, name: 'taggings_taggable_context_idx'
  13 + add_index ActsAsTaggableOn.taggings_table,
  14 + [:tag_id, :taggable_id, :taggable_type, :context, :tagger_id, :tagger_type],
  15 + unique: true, name: 'taggings_idx'
  16 + end
  17 +
  18 + def self.down
  19 + remove_index ActsAsTaggableOn.tags_table, :name
  20 +
  21 + remove_index ActsAsTaggableOn.taggings_table, name: 'taggings_idx'
  22 +
  23 + add_index ActsAsTaggableOn.taggings_table, :tag_id unless index_exists?(ActsAsTaggableOn.taggings_table, :tag_id)
  24 + add_index ActsAsTaggableOn.taggings_table, [:taggable_id, :taggable_type, :context], name: 'taggings_taggable_context_idx'
  25 + end
  26 +end
... ...
  1 +# This migration comes from acts_as_taggable_on_engine (originally 3)
  2 +if ActiveRecord.gem_version >= Gem::Version.new('5.0')
  3 + class AddTaggingsCounterCacheToTags < ActiveRecord::Migration[4.2]; end
  4 +else
  5 + class AddTaggingsCounterCacheToTags < ActiveRecord::Migration; end
  6 +end
  7 +AddTaggingsCounterCacheToTags.class_eval do
  8 + def self.up
  9 + add_column ActsAsTaggableOn.tags_table, :taggings_count, :integer, default: 0
  10 +
  11 + ActsAsTaggableOn::Tag.reset_column_information
  12 + ActsAsTaggableOn::Tag.find_each do |tag|
  13 + ActsAsTaggableOn::Tag.reset_counters(tag.id, ActsAsTaggableOn.taggings_table)
  14 + end
  15 + end
  16 +
  17 + def self.down
  18 + remove_column ActsAsTaggableOn.tags_table, :taggings_count
  19 + end
  20 +end
... ...
  1 +# This migration comes from acts_as_taggable_on_engine (originally 4)
  2 +if ActiveRecord.gem_version >= Gem::Version.new('5.0')
  3 + class AddMissingTaggableIndex < ActiveRecord::Migration[4.2]; end
  4 +else
  5 + class AddMissingTaggableIndex < ActiveRecord::Migration; end
  6 +end
  7 +AddMissingTaggableIndex.class_eval do
  8 + def self.up
  9 + add_index ActsAsTaggableOn.taggings_table, [:taggable_id, :taggable_type, :context], name: 'taggings_taggable_context_idx'
  10 + end
  11 +
  12 + def self.down
  13 + remove_index ActsAsTaggableOn.taggings_table, name: 'taggings_taggable_context_idx'
  14 + end
  15 +end
... ...
  1 +# This migration comes from acts_as_taggable_on_engine (originally 5)
  2 +# This migration is added to circumvent issue #623 and have special characters
  3 +# work properly
  4 +if ActiveRecord.gem_version >= Gem::Version.new('5.0')
  5 + class ChangeCollationForTagNames < ActiveRecord::Migration[4.2]; end
  6 +else
  7 + class ChangeCollationForTagNames < ActiveRecord::Migration; end
  8 +end
  9 +ChangeCollationForTagNames.class_eval do
  10 + def up
  11 + if ActsAsTaggableOn::Utils.using_mysql?
  12 + execute("ALTER TABLE #{ActsAsTaggableOn.tags_table} MODIFY name varchar(255) CHARACTER SET utf8 COLLATE utf8_bin;")
  13 + end
  14 + end
  15 +end
... ...
  1 +# This migration comes from acts_as_taggable_on_engine (originally 6)
  2 +if ActiveRecord.gem_version >= Gem::Version.new('5.0')
  3 + class AddMissingIndexesOnTaggings < ActiveRecord::Migration[4.2]; end
  4 +else
  5 + class AddMissingIndexesOnTaggings < ActiveRecord::Migration; end
  6 +end
  7 +AddMissingIndexesOnTaggings.class_eval do
  8 + def change
  9 + add_index ActsAsTaggableOn.taggings_table, :tag_id unless index_exists? ActsAsTaggableOn.taggings_table, :tag_id
  10 + add_index ActsAsTaggableOn.taggings_table, :taggable_id unless index_exists? ActsAsTaggableOn.taggings_table, :taggable_id
  11 + add_index ActsAsTaggableOn.taggings_table, :taggable_type unless index_exists? ActsAsTaggableOn.taggings_table, :taggable_type
  12 + add_index ActsAsTaggableOn.taggings_table, :tagger_id unless index_exists? ActsAsTaggableOn.taggings_table, :tagger_id
  13 + add_index ActsAsTaggableOn.taggings_table, :context unless index_exists? ActsAsTaggableOn.taggings_table, :context
  14 +
  15 + unless index_exists? ActsAsTaggableOn.taggings_table, [:tagger_id, :tagger_type]
  16 + add_index ActsAsTaggableOn.taggings_table, [:tagger_id, :tagger_type]
  17 + end
  18 +
  19 + unless index_exists? ActsAsTaggableOn.taggings_table, [:taggable_id, :taggable_type, :tagger_id, :context], name: 'taggings_idy'
  20 + add_index ActsAsTaggableOn.taggings_table, [:taggable_id, :taggable_type, :tagger_id, :context], name: 'taggings_idy'
  21 + end
  22 + end
  23 +end
... ...
... ... @@ -45,6 +45,8 @@ Gem::Specification.new do |s|
45 45
46 46 s.add_dependency 'unobtrusive_flash'
47 47
  48 + s.add_dependency 'acts-as-taggable-on', '~> 6.5'
  49 +
48 50 #s.add_dependency 'json'
49 51
50 52 #s.add_dependency "daemons"
... ...
1 1 require 'rails'
2 2 require 'devise'
  3 +require 'acts-as-taggable-on'
3 4
4 5 module Kanjai
5 6 class Engine < ::Rails::Engine
  7 +
6 8 isolate_namespace Kanjai
7 9 config.autoload_paths += %W(#{config.root}/lib)
8 10 #config.assets.paths << Kanjai::Engine.root.join("app", "assets", "fonts")
... ...
1 1 module Kanjai
2   - VERSION = "0.0.140"
  2 + VERSION = "0.0.141"
3 3 end
... ...
1   -== README
2   -
3   -This README would normally document whatever steps are necessary to get the
4   -application up and running.
5   -
6   -Things you may want to cover:
7   -
8   -* Ruby version
9   -
10   -* System dependencies
11   -
12   -* Configuration
13   -
14   -* Database creation
15   -
16   -* Database initialization
17   -
18   -* How to run the test suite
19   -
20   -* Services (job queues, cache servers, search engines, etc.)
21   -
22   -* Deployment instructions
23   -
24   -* ...
25   -
26   -
27   -Please feel free to use a different markup language if you do not plan to run
28   -<tt>rake doc:app</tt>.
1   -# Add your own tasks in files placed in lib/tasks ending in .rake,
2   -# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3   -
4   -require File.expand_path('../config/application', __FILE__)
5   -
6   -Rails.application.load_tasks
1   -// This is a manifest file that'll be compiled into application.js, which will include all the files
2   -// listed below.
3   -//
4   -// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5   -// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6   -//
7   -// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8   -// compiled file.
9   -//
10   -// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11   -// about supported directives.
12   -//
13   -//= require_tree .
1   -/*
2   - * This is a manifest file that'll be compiled into application.css, which will include all the files
3   - * listed below.
4   - *
5   - * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6   - * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7   - *
8   - * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9   - * compiled file so the styles you add here take precedence over styles defined in any styles
10   - * defined in the other CSS/SCSS files in this directory. It is generally better to create a new
11   - * file per style scope.
12   - *
13   - *= require_tree .
14   - *= require_self
15   - */
1   -class ApplicationController < ActionController::Base
2   - # Prevent CSRF attacks by raising an exception.
3   - # For APIs, you may want to use :null_session instead.
4   - protect_from_forgery with: :exception
5   -end
1   -module ApplicationHelper
2   -end
1   -<!DOCTYPE html>
2   -<html>
3   -<head>
4   - <title>Dummy</title>
5   - <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
6   - <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
7   - <%= csrf_meta_tags %>
8   -</head>
9   -<body>
10   -
11   -<%= yield %>
12   -
13   -</body>
14   -</html>
1   -#!/usr/bin/env ruby
2   -ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
3   -load Gem.bin_path('bundler', 'bundle')
1   -#!/usr/bin/env ruby
2   -APP_PATH = File.expand_path('../../config/application', __FILE__)
3   -require_relative '../config/boot'
4   -require 'rails/commands'
1   -#!/usr/bin/env ruby
2   -require_relative '../config/boot'
3   -require 'rake'
4   -Rake.application.run
1   -#!/usr/bin/env ruby
2   -require 'pathname'
3   -
4   -# path to your application root.
5   -APP_ROOT = Pathname.new File.expand_path('../../', __FILE__)
6   -
7   -Dir.chdir APP_ROOT do
8   - # This script is a starting point to setup your application.
9   - # Add necessary setup steps to this file:
10   -
11   - puts "== Installing dependencies =="
12   - system "gem install bundler --conservative"
13   - system "bundle check || bundle install"
14   -
15   - # puts "\n== Copying sample files =="
16   - # unless File.exist?("config/database.yml")
17   - # system "cp config/database.yml.sample config/database.yml"
18   - # end
19   -
20   - puts "\n== Preparing database =="
21   - system "bin/rake db:setup"
22   -
23   - puts "\n== Removing old logs and tempfiles =="
24   - system "rm -f log/*"
25   - system "rm -rf tmp/cache"
26   -
27   - puts "\n== Restarting application server =="
28   - system "touch tmp/restart.txt"
29   -end
1   -# This file is used by Rack-based servers to start the application.
2   -
3   -require ::File.expand_path('../config/environment', __FILE__)
4   -run Rails.application
1   -defaults: &defaults
2   - admin_email_noreply: "admin@admin.com"
3   - admin_email: "ms@edit.de"
4   - expiring_time: 60
5   - expiring_time_long: 300
6   -
7   -development:
8   - <<: *defaults
9   - domain_name: "localhost:3000"
10   -
11   -test:
12   - <<: *defaults
13   -
14   -production:
15   - <<: *defaults
16   - domain_name: <%= ENV['KANJAI_DOMAIN'] %>
1   -require File.expand_path('../boot', __FILE__)
2   -
3   -require 'rails/all'
4   -
5   -Bundler.require(*Rails.groups)
6   -require "kanjai"
7   -
8   -module Dummy
9   - class Application < Rails::Application
10   - # Settings in config/environments/* take precedence over those specified here.
11   - # Application configuration should go into files in config/initializers
12   - # -- all .rb files in that directory are automatically loaded.
13   -
14   - # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
15   - # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
16   - # config.time_zone = 'Central Time (US & Canada)'
17   -
18   - # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
19   - # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
20   - # config.i18n.default_locale = :de
21   -
22   - # Do not swallow errors in after_commit/after_rollback callbacks.
23   - config.active_record.raise_in_transactional_callbacks = true
24   - end
25   -end
26   -
1   -# Set up gems listed in the Gemfile.
2   -ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../../Gemfile', __FILE__)
3   -
4   -require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
5   -$LOAD_PATH.unshift File.expand_path('../../../../lib', __FILE__)
1   -# SQLite version 3.x
2   -# gem install sqlite3
3   -#
4   -# Ensure the SQLite 3 gem is defined in your Gemfile
5   -# gem 'sqlite3'
6   -#
7   -default: &default
8   - adapter: sqlite3
9   - pool: 5
10   - timeout: 5000
11   -
12   -development:
13   - <<: *default
14   - database: db/development.sqlite3
15   -
16   -# Warning: The database defined as "test" will be erased and
17   -# re-generated from your development database when you run "rake".
18   -# Do not set this db to the same as development or production.
19   -test:
20   - <<: *default
21   - database: db/test.sqlite3
22   -
23   -production:
24   - <<: *default
25   - database: db/production.sqlite3
1   -# Load the Rails application.
2   -require File.expand_path('../application', __FILE__)
3   -
4   -# Initialize the Rails application.
5   -Rails.application.initialize!
1   -Rails.application.configure do
2   - # Settings specified here will take precedence over those in config/application.rb.
3   -
4   - # In the development environment your application's code is reloaded on
5   - # every request. This slows down response time but is perfect for development
6   - # since you don't have to restart the web server when you make code changes.
7   - config.cache_classes = false
8   -
9   - # Do not eager load code on boot.
10   - config.eager_load = false
11   -
12   - # Show full error reports and disable caching.
13   - config.consider_all_requests_local = true
14   - config.action_controller.perform_caching = false
15   -
16   - # Don't care if the mailer can't send.
17   - config.action_mailer.raise_delivery_errors = false
18   -
19   - # Print deprecation notices to the Rails logger.
20   - config.active_support.deprecation = :log
21   -
22   - # Raise an error on page load if there are pending migrations.
23   - config.active_record.migration_error = :page_load
24   -
25   - # Debug mode disables concatenation and preprocessing of assets.
26   - # This option may cause significant delays in view rendering with a large
27   - # number of complex assets.
28   - config.assets.debug = true
29   -
30   - # Asset digests allow you to set far-future HTTP expiration dates on all assets,
31   - # yet still be able to expire them through the digest params.
32   - config.assets.digest = true
33   -
34   - # Adds additional error checking when serving assets at runtime.
35   - # Checks for improperly declared sprockets dependencies.
36   - # Raises helpful error messages.
37   - config.assets.raise_runtime_errors = true
38   -
39   - # Raises error for missing translations
40   - # config.action_view.raise_on_missing_translations = true
41   -end
1   -Rails.application.configure do
2   - # Settings specified here will take precedence over those in config/application.rb.
3   -
4   - # Code is not reloaded between requests.
5   - config.cache_classes = true
6   -
7   - # Eager load code on boot. This eager loads most of Rails and
8   - # your application in memory, allowing both threaded web servers
9   - # and those relying on copy on write to perform better.
10   - # Rake tasks automatically ignore this option for performance.
11   - config.eager_load = true
12   -
13   - # Full error reports are disabled and caching is turned on.
14   - config.consider_all_requests_local = false
15   - config.action_controller.perform_caching = true
16   -
17   - # Enable Rack::Cache to put a simple HTTP cache in front of your application
18   - # Add `rack-cache` to your Gemfile before enabling this.
19   - # For large-scale production use, consider using a caching reverse proxy like
20   - # NGINX, varnish or squid.
21   - # config.action_dispatch.rack_cache = true
22   -
23   - # Disable serving static files from the `/public` folder by default since
24   - # Apache or NGINX already handles this.
25   - config.serve_static_files = ENV['RAILS_SERVE_STATIC_FILES'].present?
26   -
27   - # Compress JavaScripts and CSS.
28   - config.assets.js_compressor = :uglifier
29   - # config.assets.css_compressor = :sass
30   -
31   - # Do not fallback to assets pipeline if a precompiled asset is missed.
32   - config.assets.compile = false
33   -
34   - # Asset digests allow you to set far-future HTTP expiration dates on all assets,
35   - # yet still be able to expire them through the digest params.
36   - config.assets.digest = true
37   -
38   - # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb
39   -
40   - # Specifies the header that your server uses for sending files.
41   - # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache
42   - # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
43   -
44   - # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
45   - # config.force_ssl = true
46   -
47   - # Use the lowest log level to ensure availability of diagnostic information
48   - # when problems arise.
49   - config.log_level = :debug
50   -
51   - # Prepend all log lines with the following tags.
52   - # config.log_tags = [ :subdomain, :uuid ]
53   -
54   - # Use a different logger for distributed setups.
55   - # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)
56   -
57   - # Use a different cache store in production.
58   - # config.cache_store = :mem_cache_store
59   -
60   - # Enable serving of images, stylesheets, and JavaScripts from an asset server.
61   - # config.action_controller.asset_host = 'http://assets.example.com'
62   -
63   - # Ignore bad email addresses and do not raise email delivery errors.
64   - # Set this to true and configure the email server for immediate delivery to raise delivery errors.
65   - # config.action_mailer.raise_delivery_errors = false
66   -
67   - # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
68   - # the I18n.default_locale when a translation cannot be found).
69   - config.i18n.fallbacks = true
70   -
71   - # Send deprecation notices to registered listeners.
72   - config.active_support.deprecation = :notify
73   -
74   - # Use default logging formatter so that PID and timestamp are not suppressed.
75   - config.log_formatter = ::Logger::Formatter.new
76   -
77   - # Do not dump schema after migrations.
78   - config.active_record.dump_schema_after_migration = false
79   -end
1   -Rails.application.configure do
2   - # Settings specified here will take precedence over those in config/application.rb.
3   -
4   - # The test environment is used exclusively to run your application's
5   - # test suite. You never need to work with it otherwise. Remember that
6   - # your test database is "scratch space" for the test suite and is wiped
7   - # and recreated between test runs. Don't rely on the data there!
8   - config.cache_classes = true
9   -
10   - # Do not eager load code on boot. This avoids loading your whole application
11   - # just for the purpose of running a single test. If you are using a tool that
12   - # preloads Rails for running tests, you may have to set it to true.
13   - config.eager_load = false
14   -
15   - # Configure static file server for tests with Cache-Control for performance.
16   - config.serve_static_files = true
17   - config.static_cache_control = 'public, max-age=3600'
18   -
19   - # Show full error reports and disable caching.
20   - config.consider_all_requests_local = true
21   - config.action_controller.perform_caching = false
22   -
23   - # Raise exceptions instead of rendering exception templates.
24   - config.action_dispatch.show_exceptions = false
25   -
26   - # Disable request forgery protection in test environment.
27   - config.action_controller.allow_forgery_protection = false
28   -
29   - # Tell Action Mailer not to deliver emails to the real world.
30   - # The :test delivery method accumulates sent emails in the
31   - # ActionMailer::Base.deliveries array.
32   - config.action_mailer.delivery_method = :test
33   -
34   - # Randomize the order test cases are executed.
35   - config.active_support.test_order = :random
36   -
37   - # Print deprecation notices to the stderr.
38   - config.active_support.deprecation = :stderr
39   -
40   - # Raises error for missing translations
41   - # config.action_view.raise_on_missing_translations = true
42   -end
1   -# Be sure to restart your server when you modify this file.
2   -
3   -# Version of your assets, change this if you want to expire all your assets.
4   -Rails.application.config.assets.version = '1.0'
5   -
6   -# Add additional assets to the asset load path
7   -# Rails.application.config.assets.paths << Emoji.images_path
8   -
9   -# Precompile additional assets.
10   -# application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
11   -# Rails.application.config.assets.precompile += %w( search.js )
1   -# Be sure to restart your server when you modify this file.
2   -
3   -# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
4   -# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
5   -
6   -# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
7   -# Rails.backtrace_cleaner.remove_silencers!
1   -# Be sure to restart your server when you modify this file.
2   -
3   -Rails.application.config.action_dispatch.cookies_serializer = :json
1   -# Be sure to restart your server when you modify this file.
2   -
3   -# Configure sensitive parameters which will be filtered from the log file.
4   -Rails.application.config.filter_parameters += [:password]
1   -# Be sure to restart your server when you modify this file.
2   -
3   -# Add new inflection rules using the following format. Inflections
4   -# are locale specific, and you may define rules for as many different
5   -# locales as you wish. All of these examples are active by default:
6   -# ActiveSupport::Inflector.inflections(:en) do |inflect|
7   -# inflect.plural /^(ox)$/i, '\1en'
8   -# inflect.singular /^(ox)en/i, '\1'
9   -# inflect.irregular 'person', 'people'
10   -# inflect.uncountable %w( fish sheep )
11   -# end
12   -
13   -# These inflection rules are supported but not enabled by default:
14   -# ActiveSupport::Inflector.inflections(:en) do |inflect|
15   -# inflect.acronym 'RESTful'
16   -# end
1   -# Be sure to restart your server when you modify this file.
2   -
3   -# Add new mime types for use in respond_to blocks:
4   -# Mime::Type.register "text/richtext", :rtf
1   -# Be sure to restart your server when you modify this file.
2   -
3   -Rails.application.config.session_store :cookie_store, key: '_dummy_session'
1   -# Be sure to restart your server when you modify this file.
2   -
3   -# This file contains settings for ActionController::ParamsWrapper which
4   -# is enabled by default.
5   -
6   -# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
7   -ActiveSupport.on_load(:action_controller) do
8   - wrap_parameters format: [:json] if respond_to?(:wrap_parameters)
9   -end
10   -
11   -# To enable root element in JSON for ActiveRecord objects.
12   -# ActiveSupport.on_load(:active_record) do
13   -# self.include_root_in_json = true
14   -# end
1   -# Files in the config/locales directory are used for internationalization
2   -# and are automatically loaded by Rails. If you want to use locales other
3   -# than English, add the necessary files in this directory.
4   -#
5   -# To use the locales, use `I18n.t`:
6   -#
7   -# I18n.t 'hello'
8   -#
9   -# In views, this is aliased to just `t`:
10   -#
11   -# <%= t('hello') %>
12   -#
13   -# To use a different locale, set it with `I18n.locale`:
14   -#
15   -# I18n.locale = :es
16   -#
17   -# This would use the information in config/locales/es.yml.
18   -#
19   -# To learn more, please read the Rails Internationalization guide
20   -# available at http://guides.rubyonrails.org/i18n.html.
21   -
22   -en:
23   - hello: "Hello world"
1   -Rails.application.routes.draw do
2   -
3   - mount Kanjai::Engine => "/kanjai"
4   -end
1   -# Be sure to restart your server when you modify this file.
2   -
3   -# Your secret key is used for verifying the integrity of signed cookies.
4   -# If you change this key, all old signed cookies will become invalid!
5   -
6   -# Make sure the secret is at least 30 characters and all random,
7   -# no regular words or you'll be exposed to dictionary attacks.
8   -# You can use `rake secret` to generate a secure secret key.
9   -
10   -# Make sure the secrets in this file are kept private
11   -# if you're sharing your code publicly.
12   -
13   -development:
14   - secret_key_base: 769e0e27e0dd0b084abe3c30e92a0cca3e5c43ac3f526d41e9c3adbcd9cd8018a11068d5c8569c9c121c1b916474fc5b78e4672e2eddc321a7cb713892b25095
15   -
16   -test:
17   - secret_key_base: 7fa42d4cf9ed143e35eee9332887e7e1564433fb78d22dad0dfaa6d72d4cbbfb8c7b9d6fcbacf30be294ee56ae95d42e325178dc13222f8d706f933ca72db4d9
18   -
19   -# Do not keep production secrets in the repository,
20   -# instead read values from the environment.
21   -production:
22   - secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
1   -<!DOCTYPE html>
2   -<html>
3   -<head>
4   - <title>The page you were looking for doesn't exist (404)</title>
5   - <meta name="viewport" content="width=device-width,initial-scale=1">
6   - <style>
7   - body {
8   - background-color: #EFEFEF;
9   - color: #2E2F30;
10   - text-align: center;
11   - font-family: arial, sans-serif;
12   - margin: 0;
13   - }
14   -
15   - div.dialog {
16   - width: 95%;
17   - max-width: 33em;
18   - margin: 4em auto 0;
19   - }
20   -
21   - div.dialog > div {
22   - border: 1px solid #CCC;
23   - border-right-color: #999;
24   - border-left-color: #999;
25   - border-bottom-color: #BBB;
26   - border-top: #B00100 solid 4px;
27   - border-top-left-radius: 9px;
28   - border-top-right-radius: 9px;
29   - background-color: white;
30   - padding: 7px 12% 0;
31   - box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
32   - }
33   -
34   - h1 {
35   - font-size: 100%;
36   - color: #730E15;
37   - line-height: 1.5em;
38   - }
39   -
40   - div.dialog > p {
41   - margin: 0 0 1em;
42   - padding: 1em;
43   - background-color: #F7F7F7;
44   - border: 1px solid #CCC;
45   - border-right-color: #999;
46   - border-left-color: #999;
47   - border-bottom-color: #999;
48   - border-bottom-left-radius: 4px;
49   - border-bottom-right-radius: 4px;
50   - border-top-color: #DADADA;
51   - color: #666;
52   - box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
53   - }
54   - </style>
55   -</head>
56   -
57   -<body>
58   - <!-- This file lives in public/404.html -->
59   - <div class="dialog">
60   - <div>
61   - <h1>The page you were looking for doesn't exist.</h1>
62   - <p>You may have mistyped the address or the page may have moved.</p>
63   - </div>
64   - <p>If you are the application owner check the logs for more information.</p>
65   - </div>
66   -</body>
67   -</html>
1   -<!DOCTYPE html>
2   -<html>
3   -<head>
4   - <title>The change you wanted was rejected (422)</title>
5   - <meta name="viewport" content="width=device-width,initial-scale=1">
6   - <style>
7   - body {
8   - background-color: #EFEFEF;
9   - color: #2E2F30;
10   - text-align: center;
11   - font-family: arial, sans-serif;
12   - margin: 0;
13   - }
14   -
15   - div.dialog {
16   - width: 95%;
17   - max-width: 33em;
18   - margin: 4em auto 0;
19   - }
20   -
21   - div.dialog > div {
22   - border: 1px solid #CCC;
23   - border-right-color: #999;
24   - border-left-color: #999;
25   - border-bottom-color: #BBB;
26   - border-top: #B00100 solid 4px;
27   - border-top-left-radius: 9px;
28   - border-top-right-radius: 9px;
29   - background-color: white;
30   - padding: 7px 12% 0;
31   - box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
32   - }
33   -
34   - h1 {
35   - font-size: 100%;
36   - color: #730E15;
37   - line-height: 1.5em;
38   - }
39   -
40   - div.dialog > p {
41   - margin: 0 0 1em;
42   - padding: 1em;
43   - background-color: #F7F7F7;
44   - border: 1px solid #CCC;
45   - border-right-color: #999;
46   - border-left-color: #999;
47   - border-bottom-color: #999;
48   - border-bottom-left-radius: 4px;
49   - border-bottom-right-radius: 4px;
50   - border-top-color: #DADADA;
51   - color: #666;
52   - box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
53   - }
54   - </style>
55   -</head>
56   -
57   -<body>
58   - <!-- This file lives in public/422.html -->
59   - <div class="dialog">
60   - <div>
61   - <h1>The change you wanted was rejected.</h1>
62   - <p>Maybe you tried to change something you didn't have access to.</p>
63   - </div>
64   - <p>If you are the application owner check the logs for more information.</p>
65   - </div>
66   -</body>
67   -</html>
1   -<!DOCTYPE html>
2   -<html>
3   -<head>
4   - <title>We're sorry, but something went wrong (500)</title>
5   - <meta name="viewport" content="width=device-width,initial-scale=1">
6   - <style>
7   - body {
8   - background-color: #EFEFEF;
9   - color: #2E2F30;
10   - text-align: center;
11   - font-family: arial, sans-serif;
12   - margin: 0;
13   - }
14   -
15   - div.dialog {
16   - width: 95%;
17   - max-width: 33em;
18   - margin: 4em auto 0;
19   - }
20   -
21   - div.dialog > div {
22   - border: 1px solid #CCC;
23   - border-right-color: #999;
24   - border-left-color: #999;
25   - border-bottom-color: #BBB;
26   - border-top: #B00100 solid 4px;
27   - border-top-left-radius: 9px;
28   - border-top-right-radius: 9px;
29   - background-color: white;
30   - padding: 7px 12% 0;
31   - box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
32   - }
33   -
34   - h1 {
35   - font-size: 100%;
36   - color: #730E15;
37   - line-height: 1.5em;
38   - }
39   -
40   - div.dialog > p {
41   - margin: 0 0 1em;
42   - padding: 1em;
43   - background-color: #F7F7F7;
44   - border: 1px solid #CCC;
45   - border-right-color: #999;
46   - border-left-color: #999;
47   - border-bottom-color: #999;
48   - border-bottom-left-radius: 4px;
49   - border-bottom-right-radius: 4px;
50   - border-top-color: #DADADA;
51   - color: #666;
52   - box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
53   - }
54   - </style>
55   -</head>
56   -
57   -<body>
58   - <!-- This file lives in public/500.html -->
59   - <div class="dialog">
60   - <div>
61   - <h1>We're sorry, but something went wrong.</h1>
62   - </div>
63   - <p>If you are the application owner check the logs for more information.</p>
64   - </div>
65   -</body>
66   -</html>
  1 +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
  2 +
  3 +# This model initially had no columns defined. If you add columns to the
  4 +# model remove the '{}' from the fixture names and add the columns immediately
  5 +# below each fixture, per the syntax in the comments below
  6 +#
  7 +one: {}
  8 +# column: value
  9 +#
  10 +two: {}
  11 +# column: value
... ...
  1 +require 'test_helper'
  2 +
  3 +module Kanjai
  4 + class TagTest < ActiveSupport::TestCase
  5 + # test "the truth" do
  6 + # assert true
  7 + # end
  8 + end
  9 +end
... ...