volt 0.9.1.pre4 → 0.9.1.pre5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +3 -0
- data/CONTRIBUTING.md +1 -1
- data/README.md +1 -0
- data/app/volt/tasks/query_tasks.rb +4 -3
- data/app/volt/tasks/store_tasks.rb +1 -1
- data/lib/volt/boot.rb +8 -7
- data/lib/volt/cli/asset_compile.rb +1 -1
- data/lib/volt/cli/console.rb +14 -3
- data/lib/volt/cli/new_gem.rb +3 -3
- data/lib/volt/cli.rb +3 -3
- data/lib/volt/config.rb +7 -1
- data/lib/volt/data_stores/base.rb +7 -0
- data/lib/volt/data_stores/data_store.rb +10 -3
- data/lib/volt/data_stores/mongo_driver.rb +58 -7
- data/lib/volt/models/associations.rb +2 -2
- data/lib/volt/models/persistors/array_store.rb +24 -6
- data/lib/volt/models/persistors/base.rb +4 -0
- data/lib/volt/models/persistors/model_store.rb +4 -15
- data/lib/volt/page/bindings/attribute_binding.rb +17 -15
- data/lib/volt/page/bindings/each_binding.rb +14 -17
- data/lib/volt/page/bindings/view_binding/controller_handler.rb +24 -0
- data/lib/volt/page/bindings/view_binding.rb +10 -30
- data/lib/volt/page/document_events.rb +7 -4
- data/lib/volt/page/page.rb +19 -13
- data/lib/volt/page/path_string_renderer.rb +41 -0
- data/lib/volt/page/targets/dom_section.rb +5 -2
- data/lib/volt/reactive/computation.rb +3 -1
- data/lib/volt/reactive/reactive_accessors.rb +8 -7
- data/lib/volt/reactive/reactive_array.rb +2 -0
- data/lib/volt/server/component_handler.rb +3 -3
- data/lib/volt/server/component_templates.rb +32 -6
- data/lib/volt/server/forking_server.rb +4 -2
- data/lib/volt/server/rack/asset_files.rb +5 -1
- data/lib/volt/server/rack/component_paths.rb +6 -4
- data/lib/volt/server/rack/opal_files.rb +16 -11
- data/lib/volt/server/rack/quiet_common_logger.rb +1 -1
- data/lib/volt/server.rb +1 -1
- data/lib/volt/spec/setup.rb +1 -1
- data/lib/volt/version.rb +5 -0
- data/lib/volt/volt/app.rb +12 -2
- data/spec/apps/kitchen_sink/app/main/views/mailers/welcome.email +12 -0
- data/spec/integration/http_endpoints_spec.rb +1 -3
- data/spec/integration/user_spec.rb +0 -10
- data/spec/models/associations_spec.rb +0 -3
- data/spec/models/model_spec.rb +13 -0
- data/spec/models/persistors/flash_spec.rb +45 -0
- data/spec/models/validators/phone_number_validator_spec.rb +2 -2
- data/spec/page/bindings/template_binding/view_lookup_for_path_spec.rb +0 -5
- data/spec/page/path_string_renderer_spec.rb +23 -0
- data/spec/page/sub_context_spec.rb +1 -0
- data/spec/router/routes_spec.rb +24 -5
- data/spec/server/html_parser/view_handler_spec.rb +20 -0
- data/spec/server/rack/quite_common_logger_spec.rb +3 -3
- data/spec/spec_helper.rb +0 -4
- data/spec/tasks/query_tracker_spec.rb +30 -0
- data/templates/newgem/lib/newgem/version.rb.tt +7 -0
- data/templates/newgem/newgem.gemspec.tt +2 -4
- data/templates/project/Gemfile.tt +5 -2
- data/templates/project/config/app.rb.tt +49 -1
- data/volt.gemspec +12 -10
- metadata +24 -28
- data/VERSION +0 -1
- data/app/volt/tasks/live_query/data_store.rb +0 -33
- data/templates/newgem/VERSION +0 -1
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 2f83c12e036d4b26d94015e199d1721c7bec82cf
         | 
| 4 | 
            +
              data.tar.gz: a6475a6f6e230f0f7d411f17a03a3bc7e15ecc3f
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 09519287d313bb3bbcdb4fc5190e67a7ab3f7d2152ddbf4a13ffecaa81fdf63043bbb2ef62d6def2fd5c28e17b048f3008e67629e12ad7b49b63c882d4c45a8d
         | 
| 7 | 
            +
              data.tar.gz: bf82e809508689cf4fc749f7dc1c6a23690e4eff81db652d6dc21ced81971195b396bfe75b5d0f6522534a63d4c480359cab8f27f6cb88058ca18b0ced74a749
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -10,6 +10,9 @@ | |
| 10 10 | 
             
            - made it so <:SectionName> can be accessed by <:section_name /> tag
         | 
| 11 11 | 
             
            - fixed issue with if bindings not resolving some promises.
         | 
| 12 12 | 
             
            - fixed issue with require's in controllers.
         | 
| 13 | 
            +
            - fix class formatting issue with Pry.
         | 
| 14 | 
            +
            - Bundler.require is now called for the correct env when 'volt/boot' is included.  (We weren't planning to do this, but it does make life so much easier)
         | 
| 15 | 
            +
            - opal-jquery was removed as a dependency.  If you want to use it again, add ```gem 'opal-jquery'``` to your Gemfile and add ```require 'opal/jquery'` to your MainController.
         | 
| 13 16 |  | 
| 14 17 |  | 
| 15 18 | 
             
            ## 0.9.0
         | 
    
        data/CONTRIBUTING.md
    CHANGED
    
    | @@ -58,7 +58,7 @@ BROWSER=firefox bundle exec rake | |
| 58 58 |  | 
| 59 59 | 
             
            #### Write Tests
         | 
| 60 60 |  | 
| 61 | 
            -
            Try to write a test that reproduces the problem you're trying to fix or describes a feature that you want to build. Add to [ | 
| 61 | 
            +
            Try to write a test that reproduces the problem you're trying to fix or describes a feature that you want to build. Add to [specs](https://github.com/voltrb/volt/tree/master/spec).
         | 
| 62 62 |  | 
| 63 63 | 
             
            We definitely appreciate pull requests that highlight or reproduce a problem, even without a fix.
         | 
| 64 64 |  | 
    
        data/README.md
    CHANGED
    
    | @@ -3,6 +3,7 @@ | |
| 3 3 | 
             
            [](https://codeclimate.com/github/voltrb/volt)
         | 
| 4 4 | 
             
            [](https://coveralls.io/r/voltrb/volt?branch=master)[](https://travis-ci.org/voltrb/volt)
         | 
| 5 5 | 
             
            [](http://inch-ci.org/github/voltrb/volt)
         | 
| 6 | 
            +
            [](http://opensource.org/licenses/MIT)
         | 
| 6 7 |  | 
| 7 8 | 
             
            For the current status of Volt, read: http://voltframework.com/blog
         | 
| 8 9 |  | 
| @@ -1,18 +1,19 @@ | |
| 1 | 
            -
            require_relative 'live_query/data_store'
         | 
| 2 1 | 
             
            require_relative 'live_query/live_query_pool'
         | 
| 3 2 |  | 
| 4 3 | 
             
            class QueryTasks < Volt::Task
         | 
| 5 | 
            -
              @@live_query_pool = LiveQueryPool.new(DataStore.new)
         | 
| 6 4 | 
             
              @@channel_live_queries = {}
         | 
| 7 5 |  | 
| 8 6 | 
             
              def self.live_query_pool
         | 
| 9 | 
            -
                @@live_query_pool
         | 
| 7 | 
            +
                @@live_query_pool ||= LiveQueryPool.new(Volt::DataStore.fetch)
         | 
| 10 8 | 
             
              end
         | 
| 11 9 |  | 
| 12 10 | 
             
              # The dispatcher passes its self in
         | 
| 13 11 | 
             
              def initialize(channel, dispatcher = nil)
         | 
| 14 12 | 
             
                @channel = channel
         | 
| 15 13 | 
             
                @dispatcher = dispatcher
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                # Load the query pool if not already setup
         | 
| 16 | 
            +
                self.class.live_query_pool
         | 
| 16 17 | 
             
              end
         | 
| 17 18 |  | 
| 18 19 | 
             
              def add_listener(collection, query)
         | 
    
        data/lib/volt/boot.rb
    CHANGED
    
    | @@ -1,3 +1,11 @@ | |
| 1 | 
            +
            unless RUBY_PLATFORM == 'opal'
         | 
| 2 | 
            +
              # An option to skip requiring.
         | 
| 3 | 
            +
              unless ENV['SKIP_BUNDLER_REQUIRE']
         | 
| 4 | 
            +
                # Require in gems
         | 
| 5 | 
            +
                Bundler.require((ENV['VOLT_ENV'] || ENV['RACK_ENV'] || :development).to_sym)
         | 
| 6 | 
            +
              end
         | 
| 7 | 
            +
            end
         | 
| 8 | 
            +
             | 
| 1 9 | 
             
            require 'volt/models'
         | 
| 2 10 | 
             
            require 'volt/server/rack/component_paths'
         | 
| 3 11 |  | 
| @@ -10,13 +18,6 @@ require 'volt/volt/app' | |
| 10 18 |  | 
| 11 19 | 
             
            module Volt
         | 
| 12 20 | 
             
              def self.boot(app_path)
         | 
| 13 | 
            -
                # Run the app config to load all users config files
         | 
| 14 | 
            -
                unless RUBY_PLATFORM == 'opal'
         | 
| 15 | 
            -
                  if Volt.server?
         | 
| 16 | 
            -
                    $page = Page.new
         | 
| 17 | 
            -
                  end
         | 
| 18 | 
            -
                end
         | 
| 19 | 
            -
             | 
| 20 21 | 
             
                # Boot the app
         | 
| 21 22 | 
             
                App.new(app_path)
         | 
| 22 23 | 
             
              end
         | 
| @@ -80,7 +80,7 @@ module Volt | |
| 80 80 | 
             
                end
         | 
| 81 81 |  | 
| 82 82 | 
             
                def write_component_js
         | 
| 83 | 
            -
                  javascript_code = @component_handler.compile_for_component('main')
         | 
| 83 | 
            +
                  javascript_code = @component_handler.compile_for_component('main', true)
         | 
| 84 84 |  | 
| 85 85 | 
             
                  path = File.join(Volt.root, '/public/components/main.js')
         | 
| 86 86 | 
             
                  write_file(path, javascript_code)
         | 
    
        data/lib/volt/cli/console.rb
    CHANGED
    
    | @@ -29,6 +29,17 @@ end | |
| 29 29 |  | 
| 30 30 | 
             
            module Volt
         | 
| 31 31 | 
             
              class Console
         | 
| 32 | 
            +
                module Helpers
         | 
| 33 | 
            +
                  def store
         | 
| 34 | 
            +
                    $page.store
         | 
| 35 | 
            +
                  end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                  def page
         | 
| 38 | 
            +
                    $page.page
         | 
| 39 | 
            +
                  end
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
             | 
| 32 43 | 
             
                def self.start
         | 
| 33 44 | 
             
                  require 'pry'
         | 
| 34 45 |  | 
| @@ -46,10 +57,10 @@ module Volt | |
| 46 57 |  | 
| 47 58 | 
             
                  Pry.config.prompt_name = 'volt'
         | 
| 48 59 |  | 
| 49 | 
            -
                   | 
| 50 | 
            -
                  # Pry.start
         | 
| 60 | 
            +
                  Pry.main.send(:include, Volt::Console::Helpers)
         | 
| 51 61 |  | 
| 52 | 
            -
                  $page.pry
         | 
| 62 | 
            +
                  # $page.pry
         | 
| 63 | 
            +
                  Pry.start
         | 
| 53 64 | 
             
                end
         | 
| 54 65 | 
             
              end
         | 
| 55 66 | 
             
            end
         | 
    
        data/lib/volt/cli/new_gem.rb
    CHANGED
    
    | @@ -51,8 +51,8 @@ class NewGem | |
| 51 51 | 
             
                copy('newgem/gitignore.tt', '.gitignore')
         | 
| 52 52 | 
             
                copy('newgem/newgem.gemspec.tt', "#{@name}.gemspec")
         | 
| 53 53 | 
             
                copy('newgem/lib/newgem.rb.tt', "lib/#{@namespaced_path}.rb")
         | 
| 54 | 
            -
                copy('newgem/VERSION', 'VERSION')
         | 
| 55 54 | 
             
                FileUtils.mkdir_p(File.join(@target, "lib/#{@namespaced_path}"))
         | 
| 55 | 
            +
                copy('newgem/lib/newgem/version.rb.tt', "lib/#{@namespaced_path}/version.rb")
         | 
| 56 56 | 
             
              end
         | 
| 57 57 |  | 
| 58 58 | 
             
              def copy_options
         | 
| @@ -103,8 +103,8 @@ class NewGem | |
| 103 103 | 
             
              end
         | 
| 104 104 |  | 
| 105 105 | 
             
              def volt_version_base
         | 
| 106 | 
            -
                 | 
| 107 | 
            -
                 | 
| 106 | 
            +
                require 'volt/version'
         | 
| 107 | 
            +
                Volt::Version::STRING.split('.').tap { |v| v[v.size - 1] = 0 }.join('.')
         | 
| 108 108 | 
             
              end
         | 
| 109 109 |  | 
| 110 110 | 
             
              def get_constant_name
         | 
    
        data/lib/volt/cli.rb
    CHANGED
    
    | @@ -4,6 +4,7 @@ require 'bundler/setup' | |
| 4 4 | 
             
            require 'thor'
         | 
| 5 5 | 
             
            require 'volt/extra_core/extra_core'
         | 
| 6 6 | 
             
            require 'volt/cli/generate'
         | 
| 7 | 
            +
            require 'volt/version'
         | 
| 7 8 |  | 
| 8 9 | 
             
            module Volt
         | 
| 9 10 | 
             
              class CLI < Thor
         | 
| @@ -17,8 +18,7 @@ module Volt | |
| 17 18 | 
             
                  require 'securerandom'
         | 
| 18 19 |  | 
| 19 20 | 
             
                  # Grab the current volt version
         | 
| 20 | 
            -
                  version  | 
| 21 | 
            -
                  directory('project', name, version: version, name: name)
         | 
| 21 | 
            +
                  directory('project', name, version: Volt::Version::STRING, name: name, domain: name.dasherize.downcase, app_name: name.capitalize)
         | 
| 22 22 |  | 
| 23 23 | 
             
                  say 'Bundling Gems...'
         | 
| 24 24 | 
             
                  `cd #{name} && bundle`
         | 
| @@ -114,5 +114,5 @@ end | |
| 114 114 | 
             
            # Add in more features
         | 
| 115 115 | 
             
            require 'volt/cli/asset_compile'
         | 
| 116 116 |  | 
| 117 | 
            -
            puts "Volt #{ | 
| 117 | 
            +
            puts "Volt #{Volt::Version::STRING}"
         | 
| 118 118 | 
             
            Volt::CLI.start(ARGV)
         | 
    
        data/lib/volt/config.rb
    CHANGED
    
    | @@ -51,7 +51,13 @@ else | |
| 51 51 | 
             
                      db_name:   (ENV['DB_NAME'] || (app_name + '_' + Volt.env.to_s)).gsub('.', '_'),
         | 
| 52 52 | 
             
                      db_host:   ENV['DB_HOST'] || 'localhost',
         | 
| 53 53 | 
             
                      db_port:   (ENV['DB_PORT'] || 27_017).to_i,
         | 
| 54 | 
            -
                      db_driver: ENV['DB_DRIVER'] || 'mongo'
         | 
| 54 | 
            +
                      db_driver: ENV['DB_DRIVER'] || 'mongo',
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                      # a list of components which should be included in all components
         | 
| 57 | 
            +
                      default_components: ['volt'],
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                      compress_javascript: Volt.env.production?,
         | 
| 60 | 
            +
                      compress_css:        Volt.env.production?
         | 
| 55 61 | 
             
                    }
         | 
| 56 62 | 
             
                  end
         | 
| 57 63 |  | 
| @@ -3,9 +3,16 @@ require 'volt/data_stores/mongo_driver' | |
| 3 3 | 
             
            module Volt
         | 
| 4 4 | 
             
              class DataStore
         | 
| 5 5 | 
             
                def self.fetch
         | 
| 6 | 
            -
                   | 
| 7 | 
            -
             | 
| 8 | 
            -
             | 
| 6 | 
            +
                  # Cache the driver
         | 
| 7 | 
            +
                  return @driver if @driver
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  database_name = Volt.config.db_driver
         | 
| 10 | 
            +
                  driver_name = database_name.camelize + 'Driver'
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  begin
         | 
| 13 | 
            +
                    driver = self.const_get(driver_name)
         | 
| 14 | 
            +
                    @driver = MongoDriver.new
         | 
| 15 | 
            +
                  rescue NameError => e
         | 
| 9 16 | 
             
                    fail "#{database_name} is not a supported database"
         | 
| 10 17 | 
             
                  end
         | 
| 11 18 | 
             
                end
         | 
| @@ -1,17 +1,68 @@ | |
| 1 | 
            +
            require 'volt/data_stores/base'
         | 
| 1 2 | 
             
            require 'mongo'
         | 
| 2 3 |  | 
| 3 4 | 
             
            module Volt
         | 
| 4 5 | 
             
              class DataStore
         | 
| 5 | 
            -
                class MongoDriver
         | 
| 6 | 
            -
                   | 
| 6 | 
            +
                class MongoDriver < Base
         | 
| 7 | 
            +
                  attr_reader :db, :mongo_db
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  def initialize
         | 
| 7 10 | 
             
                    if Volt.config.db_uri.present?
         | 
| 8 | 
            -
                       | 
| 9 | 
            -
                       | 
| 11 | 
            +
                      @mongo_db ||= Mongo::MongoClient.from_uri(Volt.config.db_uri)
         | 
| 12 | 
            +
                      @db ||= @mongo_db.db(Volt.config.db_uri.split('/').last || Volt.config.db_name)
         | 
| 10 13 | 
             
                    else
         | 
| 11 | 
            -
                       | 
| 12 | 
            -
                       | 
| 14 | 
            +
                      @mongo_db ||= Mongo::MongoClient.new(Volt.config.db_host, Volt.config.db_path)
         | 
| 15 | 
            +
                      @db ||= @mongo_db.db(Volt.config.db_name)
         | 
| 16 | 
            +
                    end
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  def insert(collection, values)
         | 
| 20 | 
            +
                    @db[collection].insert(values)
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  def update(collection, values)
         | 
| 24 | 
            +
                    # TODO: Seems mongo is dumb and doesn't let you upsert with custom id's
         | 
| 25 | 
            +
                    begin
         | 
| 26 | 
            +
                      @db[collection].insert(values)
         | 
| 27 | 
            +
                    rescue Mongo::OperationFailure => error
         | 
| 28 | 
            +
                      # Really mongo client?
         | 
| 29 | 
            +
                      if error.message[/^11000[:]/]
         | 
| 30 | 
            +
                        # Update because the id already exists
         | 
| 31 | 
            +
                        update_values = values.dup
         | 
| 32 | 
            +
                        id = update_values.delete(:_id)
         | 
| 33 | 
            +
                        @db[collection].update({ _id: id }, update_values)
         | 
| 34 | 
            +
                      else
         | 
| 35 | 
            +
                        return { error: error.message }
         | 
| 36 | 
            +
                      end
         | 
| 13 37 | 
             
                    end
         | 
| 14 | 
            -
             | 
| 38 | 
            +
             | 
| 39 | 
            +
                    return nil
         | 
| 40 | 
            +
                  end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                  def query(collection, query)
         | 
| 43 | 
            +
                    allowed_methods = ['find', 'skip', 'limit']
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                    cursor = @db[collection]
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                    query.each do |query_part|
         | 
| 48 | 
            +
                      method_name, *args = query_part
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                      unless allowed_methods.include?(method_name.to_s)
         | 
| 51 | 
            +
                        raise "`#{method_name}` is not part of a valid query"
         | 
| 52 | 
            +
                      end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                      cursor = cursor.send(method_name, *args)
         | 
| 55 | 
            +
                    end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                    cursor.to_a
         | 
| 58 | 
            +
                  end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                  def delete(collection, query)
         | 
| 61 | 
            +
                    @db[collection].remove(query)
         | 
| 62 | 
            +
                  end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                  def drop_database
         | 
| 65 | 
            +
                    db.connection.drop_database(Volt.config.db_name)
         | 
| 15 66 | 
             
                  end
         | 
| 16 67 | 
             
                end
         | 
| 17 68 | 
             
              end
         | 
| @@ -36,7 +36,7 @@ module Volt | |
| 36 36 | 
             
                # Currently the has_many and belongs_to associations only work on the store collection,
         | 
| 37 37 | 
             
                # this method checks to make sure we are on store and returns the root reference to it.
         | 
| 38 38 | 
             
                def association_with_root_model(method_name)
         | 
| 39 | 
            -
                  persistor = self.persistor || (respond_to(:save_to) && save_to.persistor)
         | 
| 39 | 
            +
                  persistor = self.persistor || (respond_to?(:save_to) && save_to.persistor)
         | 
| 40 40 |  | 
| 41 41 | 
             
                  # Check if we are on the store collection
         | 
| 42 42 | 
             
                  if persistor.is_a?(Volt::Persistors::ModelStore)
         | 
| @@ -51,4 +51,4 @@ module Volt | |
| 51 51 | 
             
                  end
         | 
| 52 52 | 
             
                end
         | 
| 53 53 | 
             
              end
         | 
| 54 | 
            -
            end
         | 
| 54 | 
            +
            end
         | 
| @@ -18,6 +18,9 @@ module Volt | |
| 18 18 | 
             
                  end
         | 
| 19 19 |  | 
| 20 20 | 
             
                  def initialize(model, tasks = nil)
         | 
| 21 | 
            +
                    # Keep a hash of all ids in this collection
         | 
| 22 | 
            +
                    @ids = {}
         | 
| 23 | 
            +
             | 
| 21 24 | 
             
                    super
         | 
| 22 25 |  | 
| 23 26 | 
             
                    # The listener event counter keeps track of how many things are listening
         | 
| @@ -226,15 +229,16 @@ module Volt | |
| 226 229 | 
             
                  # TODO: Deprecate
         | 
| 227 230 | 
             
                  alias_method :then, :fetch
         | 
| 228 231 |  | 
| 229 | 
            -
                  # Called from backend
         | 
| 232 | 
            +
                  # Called from backend when an item is added
         | 
| 230 233 | 
             
                  def add(index, data)
         | 
| 231 234 | 
             
                    $loading_models = true
         | 
| 232 235 |  | 
| 233 236 | 
             
                    Model.no_validate do
         | 
| 234 237 | 
             
                      data_id = data['_id'] || data[:_id]
         | 
| 235 238 |  | 
| 236 | 
            -
                      # Don't add if the model is already in the ArrayModel
         | 
| 237 | 
            -
                      unless @ | 
| 239 | 
            +
                      # Don't add if the model is already in the ArrayModel (from the client already)
         | 
| 240 | 
            +
                      unless @ids[data_id]
         | 
| 241 | 
            +
                        @ids[data_id] = true
         | 
| 238 242 | 
             
                        # Find the existing model, or create one
         | 
| 239 243 | 
             
                        new_model = @@identity_map.find(data_id) do
         | 
| 240 244 | 
             
                          new_options = @model.options.merge(path: @model.path + [:[]], parent: @model)
         | 
| @@ -248,12 +252,14 @@ module Volt | |
| 248 252 | 
             
                    $loading_models = false
         | 
| 249 253 | 
             
                  end
         | 
| 250 254 |  | 
| 255 | 
            +
                  # Called from the server when it removes an item.
         | 
| 251 256 | 
             
                  def remove(ids)
         | 
| 252 257 | 
             
                    $loading_models = true
         | 
| 253 258 | 
             
                    ids.each do |id|
         | 
| 254 259 | 
             
                      # TODO: optimize this delete so we don't need to loop
         | 
| 255 260 | 
             
                      @model.each_with_index do |model, index|
         | 
| 256 261 | 
             
                        if model._id == id
         | 
| 262 | 
            +
                          @ids.delete(id)
         | 
| 257 263 | 
             
                          del = @model.delete_at(index)
         | 
| 258 264 | 
             
                          break
         | 
| 259 265 | 
             
                        end
         | 
| @@ -263,23 +269,35 @@ module Volt | |
| 263 269 | 
             
                    $loading_models = false
         | 
| 264 270 | 
             
                  end
         | 
| 265 271 |  | 
| 272 | 
            +
                  # Called when all models are removed
         | 
| 273 | 
            +
                  def clear
         | 
| 274 | 
            +
                    @ids = {}
         | 
| 275 | 
            +
                  end
         | 
| 276 | 
            +
             | 
| 266 277 | 
             
                  def channel_name
         | 
| 267 278 | 
             
                    @model.path[-1]
         | 
| 268 279 | 
             
                  end
         | 
| 269 280 |  | 
| 270 | 
            -
                  #  | 
| 271 | 
            -
                  # method.  This should trigger a save.
         | 
| 281 | 
            +
                  # Called when the client adds an item.
         | 
| 272 282 | 
             
                  def added(model, index)
         | 
| 273 283 | 
             
                    if model.persistor
         | 
| 274 284 | 
             
                      # Tell the persistor it was added, return the promise
         | 
| 275 | 
            -
                      model.persistor.add_to_collection
         | 
| 285 | 
            +
                      promise = model.persistor.add_to_collection
         | 
| 286 | 
            +
             | 
| 287 | 
            +
                      # Track the the model got added
         | 
| 288 | 
            +
                      @ids[model._id] = true
         | 
| 289 | 
            +
             | 
| 290 | 
            +
                      promise
         | 
| 276 291 | 
             
                    end
         | 
| 277 292 | 
             
                  end
         | 
| 278 293 |  | 
| 294 | 
            +
                  # Called when the client removes an item
         | 
| 279 295 | 
             
                  def removed(model)
         | 
| 280 296 | 
             
                    if model.persistor
         | 
| 281 297 | 
             
                      # Tell the persistor it was removed
         | 
| 282 298 | 
             
                      model.persistor.remove_from_collection
         | 
| 299 | 
            +
             | 
| 300 | 
            +
                      @ids.delete(model._id)
         | 
| 283 301 | 
             
                    end
         | 
| 284 302 |  | 
| 285 303 | 
             
                    if defined?($loading_models) && $loading_models
         | 
| @@ -195,21 +195,10 @@ module Volt | |
| 195 195 | 
             
                      id = values[:_id]
         | 
| 196 196 |  | 
| 197 197 | 
             
                      # Try to create
         | 
| 198 | 
            -
                       | 
| 199 | 
            -
             | 
| 200 | 
            -
             | 
| 201 | 
            -
             | 
| 202 | 
            -
                      rescue Mongo::OperationFailure => error
         | 
| 203 | 
            -
                        # Really mongo client?
         | 
| 204 | 
            -
                        if error.message[/^11000[:]/]
         | 
| 205 | 
            -
                          # Update because the id already exists
         | 
| 206 | 
            -
                          update_values = values.dup
         | 
| 207 | 
            -
                          update_values.delete(:_id)
         | 
| 208 | 
            -
                          db[collection].update({ _id: id }, update_values)
         | 
| 209 | 
            -
                        else
         | 
| 210 | 
            -
                          return { error: error.message }
         | 
| 211 | 
            -
                        end
         | 
| 212 | 
            -
                      end
         | 
| 198 | 
            +
                      update_result = db.update(collection, values)
         | 
| 199 | 
            +
             | 
| 200 | 
            +
                      # An error hash will be returned if the update doesn't work
         | 
| 201 | 
            +
                      return update_result if update_result
         | 
| 213 202 |  | 
| 214 203 | 
             
                      QueryTasks.live_query_pool.updated_collection(collection.to_s, Thread.current['in_channel'])
         | 
| 215 204 | 
             
                      {}
         | 
| @@ -26,26 +26,28 @@ module Volt | |
| 26 26 | 
             
                    update(result)
         | 
| 27 27 | 
             
                  end
         | 
| 28 28 |  | 
| 29 | 
            -
                  @is_radio = element.is('[type=radio]')
         | 
| 29 | 
            +
                  @is_radio = `#{element}.is('[type=radio]')`
         | 
| 30 30 | 
             
                  if @is_radio
         | 
| 31 | 
            -
                    @selected_value = element.attr('value')
         | 
| 31 | 
            +
                    @selected_value = `#{element}.attr('value') || ''`
         | 
| 32 32 | 
             
                  end
         | 
| 33 33 |  | 
| 34 34 | 
             
                  # Bind so when this value updates, we update
         | 
| 35 35 | 
             
                  case @attribute_name
         | 
| 36 36 | 
             
                    when 'value'
         | 
| 37 | 
            -
                       | 
| 37 | 
            +
                      changed_event = Proc.new { changed }
         | 
| 38 | 
            +
                      `#{element}.on('input.attrbind', #{changed_event})`
         | 
| 38 39 | 
             
                    when 'checked'
         | 
| 39 | 
            -
                       | 
| 40 | 
            +
                      changed_event = Proc.new { |event| changed(event) }
         | 
| 41 | 
            +
                      `#{element}.on('change.attrbind', #{changed_event})`
         | 
| 40 42 | 
             
                  end
         | 
| 41 43 | 
             
                end
         | 
| 42 44 |  | 
| 43 45 | 
             
                def changed(event = nil)
         | 
| 44 46 | 
             
                  case @attribute_name
         | 
| 45 47 | 
             
                    when 'value'
         | 
| 46 | 
            -
                      current_value = element. | 
| 48 | 
            +
                      current_value = `#{element}.val() || ''`
         | 
| 47 49 | 
             
                    else
         | 
| 48 | 
            -
                      current_value = element.is(':checked')
         | 
| 50 | 
            +
                      current_value = `#{element}.is(':checked')`
         | 
| 49 51 | 
             
                  end
         | 
| 50 52 |  | 
| 51 53 | 
             
                  if @is_radio
         | 
| @@ -59,7 +61,7 @@ module Volt | |
| 59 61 | 
             
                end
         | 
| 60 62 |  | 
| 61 63 | 
             
                def element
         | 
| 62 | 
            -
                   | 
| 64 | 
            +
                  @element ||= `$('#' + #{binding_name})`
         | 
| 63 65 | 
             
                end
         | 
| 64 66 |  | 
| 65 67 | 
             
                def update(new_value)
         | 
| @@ -94,20 +96,20 @@ module Volt | |
| 94 96 | 
             
                    when 'value'
         | 
| 95 97 | 
             
                      # TODO: only update if its not the same, this keeps it from moving the
         | 
| 96 98 | 
             
                      # cursor in text fields.
         | 
| 97 | 
            -
                      if val != element. | 
| 98 | 
            -
                        element. | 
| 99 | 
            +
                      if val != `(#{element}.val() || '')`
         | 
| 100 | 
            +
                        `#{element}.val(#{val})`
         | 
| 99 101 | 
             
                      end
         | 
| 100 102 | 
             
                    when 'disabled'
         | 
| 101 103 | 
             
                      # Disabled is handled specially, you can either return a boolean:
         | 
| 102 104 | 
             
                      # (true being disabled, false not disabled), or you can optionally
         | 
| 103 105 | 
             
                      # include the "disabled" string. (or any string)
         | 
| 104 106 | 
             
                      if val != false && val.present?
         | 
| 105 | 
            -
                        element.attr('disabled', 'disabled')
         | 
| 107 | 
            +
                        `#{element}.attr('disabled', 'disabled')`
         | 
| 106 108 | 
             
                      else
         | 
| 107 | 
            -
                        element. | 
| 109 | 
            +
                        `#{element}.removeAttr('disabled')`
         | 
| 108 110 | 
             
                      end
         | 
| 109 111 | 
             
                    else
         | 
| 110 | 
            -
                      element | 
| 112 | 
            +
                      `#{element}.attr(#{@attribute_name}, #{val})`
         | 
| 111 113 | 
             
                  end
         | 
| 112 114 | 
             
                end
         | 
| 113 115 |  | 
| @@ -120,7 +122,7 @@ module Volt | |
| 120 122 | 
             
                    value = (@selected_value == value)
         | 
| 121 123 | 
             
                  end
         | 
| 122 124 |  | 
| 123 | 
            -
                  element.prop('checked', value)
         | 
| 125 | 
            +
                  `#{element}.prop('checked', #{value})`
         | 
| 124 126 | 
             
                end
         | 
| 125 127 |  | 
| 126 128 | 
             
                def remove
         | 
| @@ -128,9 +130,9 @@ module Volt | |
| 128 130 | 
             
                  # aren't responsible for it being there.
         | 
| 129 131 | 
             
                  case @attribute_name
         | 
| 130 132 | 
             
                    when 'value'
         | 
| 131 | 
            -
                      element.off('input.attrbind', nil)
         | 
| 133 | 
            +
                      `#{element}.off('input.attrbind', #{nil})`
         | 
| 132 134 | 
             
                    when 'checked'
         | 
| 133 | 
            -
                      element.off('change.attrbind', nil)
         | 
| 135 | 
            +
                      `#{element}.off('change.attrbind', #{nil})`
         | 
| 134 136 | 
             
                  end
         | 
| 135 137 |  | 
| 136 138 | 
             
                  if @computation
         | 
| @@ -31,16 +31,10 @@ module Volt | |
| 31 31 | 
             
                  Computation.run_without_tracking do
         | 
| 32 32 | 
             
                    # Adjust to the new size
         | 
| 33 33 | 
             
                    values = current_values(value)
         | 
| 34 | 
            +
             | 
| 34 35 | 
             
                    @value = values
         | 
| 35 36 |  | 
| 36 | 
            -
                     | 
| 37 | 
            -
                      @added_listener.remove
         | 
| 38 | 
            -
                      @added_listener = nil
         | 
| 39 | 
            -
                    end
         | 
| 40 | 
            -
                    if @removed_listener
         | 
| 41 | 
            -
                      @removed_listener.remove
         | 
| 42 | 
            -
                      @removed_listener = nil
         | 
| 43 | 
            -
                    end
         | 
| 37 | 
            +
                    remove_listeners
         | 
| 44 38 |  | 
| 45 39 | 
             
                    if @value.respond_to?(:on)
         | 
| 46 40 | 
             
                      @added_listener   = @value.on('added') { |position| item_added(position) }
         | 
| @@ -141,6 +135,17 @@ module Volt | |
| 141 135 | 
             
                  values
         | 
| 142 136 | 
             
                end
         | 
| 143 137 |  | 
| 138 | 
            +
                def remove_listeners
         | 
| 139 | 
            +
                  if @added_listener
         | 
| 140 | 
            +
                    @added_listener.remove
         | 
| 141 | 
            +
                    @added_listener = nil
         | 
| 142 | 
            +
                  end
         | 
| 143 | 
            +
                  if @removed_listener
         | 
| 144 | 
            +
                    @removed_listener.remove
         | 
| 145 | 
            +
                    @removed_listener = nil
         | 
| 146 | 
            +
                  end
         | 
| 147 | 
            +
                end
         | 
| 148 | 
            +
             | 
| 144 149 | 
             
                # When this each_binding is removed, cleanup.
         | 
| 145 150 | 
             
                def remove
         | 
| 146 151 | 
             
                  @computation.stop
         | 
| @@ -151,15 +156,7 @@ module Volt | |
| 151 156 |  | 
| 152 157 | 
             
                  @getter = nil
         | 
| 153 158 |  | 
| 154 | 
            -
                   | 
| 155 | 
            -
                    @added_listener.remove
         | 
| 156 | 
            -
                    @added_listener = nil
         | 
| 157 | 
            -
                  end
         | 
| 158 | 
            -
             | 
| 159 | 
            -
                  if @removed_listener
         | 
| 160 | 
            -
                    @removed_listener.remove
         | 
| 161 | 
            -
                    @removed_listener = nil
         | 
| 162 | 
            -
                  end
         | 
| 159 | 
            +
                  remove_listeners
         | 
| 163 160 |  | 
| 164 161 | 
             
                  if @templates
         | 
| 165 162 | 
             
                    template_count = @templates.size
         | 
| @@ -40,5 +40,29 @@ module Volt | |
| 40 40 | 
             
                  # before_action chain was not stopped
         | 
| 41 41 | 
             
                  return false
         | 
| 42 42 | 
             
                end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                # Fetch the controller class
         | 
| 45 | 
            +
                def self.get_controller_and_action(controller_path)
         | 
| 46 | 
            +
                  raise "Invalid controller path: #{controller_path.inspect}" unless controller_path && controller_path.size > 0
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                  action = controller_path[-1]
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                  # Get the constant parts
         | 
| 51 | 
            +
                  parts  = controller_path[0..-2].map { |v| v.tr('-', '_').camelize }
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                  # Do const lookups starting at object and working our way down.
         | 
| 54 | 
            +
                  # So Volt::ProgressBar would lookup Volt, then ProgressBar on Volt.
         | 
| 55 | 
            +
                  obj = Object
         | 
| 56 | 
            +
                  parts.each do |part|
         | 
| 57 | 
            +
                    if obj.const_defined?(part)
         | 
| 58 | 
            +
                      obj = obj.const_get(part)
         | 
| 59 | 
            +
                    else
         | 
| 60 | 
            +
                      # return a blank ModelController
         | 
| 61 | 
            +
                      return [ModelController, nil]
         | 
| 62 | 
            +
                    end
         | 
| 63 | 
            +
                  end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                  [obj, action]
         | 
| 66 | 
            +
                end
         | 
| 43 67 | 
             
              end
         | 
| 44 68 | 
             
            end
         |