OSDN Git Service

add comic story
authoryasushiito <yas@pen-chan.jp>
Sun, 25 May 2014 06:20:15 +0000 (15:20 +0900)
committeryasushiito <yas@pen-chan.jp>
Sun, 25 May 2014 06:20:15 +0000 (15:20 +0900)
19 files changed:
1  2 
app/assets/javascripts/manifest/work/controllers.js.coffee.erb
app/assets/javascripts/manifest/work/list_groups.js.coffee.erb
app/assets/javascripts/manifest/work/profilers.js.coffee.erb
app/controllers/comic_stories_controller.rb
app/controllers/comics_controller.rb
app/controllers/stories_controller.rb
app/models/comic_story.rb
app/models/scroll_panel.rb
app/models/sheet_panel.rb
app/models/story_sheet.rb
app/views/comic_stories/_append_comic.html.erb
app/views/comic_stories/_append_story.html.erb
app/views/comics/show.html.erb
app/views/stories/play.html.erb
app/views/stories/show.html.erb
config/locales/pettanr.ja.yml
config/routes.rb
public/local_manifest.json
public/manifest.json

            \r
          },\r
        },\r
 +      by_story: {\r
 +        type: 'list',\r
 +      },\r
 +      by_author: {\r
 +        type: 'list',\r
 +      },\r
++      play: {\r
++        type: 'list',\r
++        args: {\r
++          item_name: 'comic_story',\r
++          list_name: 'play',\r
++        },\r
++      },\r
 +      show: {\r
 +        type: 'show',\r
 +      },\r
 +      count: {\r
 +        type: 'count',\r
 +        args: {\r
 +          list_name: 'public',\r
 +        },\r
 +      },\r
 +      count_by_story: {\r
 +        type: 'count',\r
 +      },\r
 +      count_by_author: {\r
 +        type: 'count',\r
 +      },\r
 +      new: {\r
 +        type: 'new',\r
 +      },\r
 +      edit: {\r
 +        type: 'edit',\r
 +      },\r
 +    },\r
 +  },\r
 +  comic_stories: {\r
 +    actions: {\r
 +      index: {\r
 +        type: 'list',\r
 +        args: {\r
 +          list_name: 'public',\r
 +          \r
 +        },\r
 +      },\r
 +      by_comic: {\r
 +        type: 'list',\r
 +      },\r
 +      by_story: {\r
 +        type: 'list',\r
 +      },\r
        by_author: {\r
          type: 'list',\r
        },\r
            list_name: 'public',\r
          },\r
        },\r
 +      count_by_comic: {\r
 +        type: 'count',\r
 +      },\r
 +      count_by_story: {\r
 +        type: 'count',\r
 +      },\r
        count_by_author: {\r
          type: 'count',\r
        },\r
            list_name: 'public',\r
          },\r
        },\r
 -      by_comic: {\r
 +      count_by_comic: {\r
          type: 'count',\r
        },\r
 -      by_sheet: {\r
 +      count_by_sheet: {\r
          type: 'count',\r
        },\r
        count_by_author: {\r
            \r
          },\r
        },\r
-       scrolls: {\r
-         type: 'list',\r
-         args: {\r
-           list_name: 'scrolls',\r
-         },\r
-       },\r
-       comics: {\r
-         type: 'list',\r
-         args: {\r
-           list_name: 'comics',\r
-         },\r
-       },\r
-       stories: {\r
-         type: 'list',\r
-         args: {\r
-           list_name: 'stories',\r
-         },\r
-       },\r
-       sheets: {\r
-         type: 'list',\r
-         args: {\r
-           list_name: 'sheets',\r
-         },\r
-       },\r
-       panels: {\r
-         type: 'list',\r
-         args: {\r
-           list_name: 'panels',\r
-         },\r
-       },\r
-       panel_pictures: {\r
-         type: 'list',\r
-         args: {\r
-           list_name: 'panel_pictures',\r
-         },\r
-       },\r
-       speech_balloons: {\r
-         type: 'list',\r
-         args: {\r
-           list_name: 'speech_balloons',\r
-         },\r
-       },\r
-       ground_pictures: {\r
-         type: 'list',\r
-         args: {\r
-           list_name: 'ground_pictures',\r
-         },\r
-       },\r
-       ground_colors: {\r
-         type: 'list',\r
-         args: {\r
-           list_name: 'ground_colors',\r
-         },\r
-       },\r
        show: {\r
          type: 'show',\r
        },\r
            \r
          },\r
        },\r
-       resource_pictures: {\r
-         type: 'list',\r
-         args: {\r
-           list_name: 'resource_pictures',\r
-         },\r
-       },\r
        show: {\r
          type: 'show',\r
        },\r
        by_author: {\r
          type: 'filter',\r
        },\r
 +      by_story: {\r
 +        type: 'through_filter',\r
 +        args: {\r
 +          through: 'comic_stories',\r
 +        },\r
 +      },\r
      },\r
    },\r
 -  story: {\r
 +  comic_story: {\r
      lists: {\r
        public: {\r
          type: 'public',\r
        private: {\r
          type: 'private',\r
        },\r
 +      play: {\r
 +        type: 'play',\r
 +        args: {\r
 +          filter_item_name: 'comic',\r
 +          filter_model_name: 'comic_story',\r
 +          filter_key: 'comic_id',\r
 +        },\r
 +      },\r
        by_comic: {\r
          type: 'filter',\r
        },\r
 -      by_sheet: {\r
 -        type: 'through_filter',\r
 -        args: {\r
 -          through: 'story_sheets',\r
 -        },\r
 +      by_story: {\r
 +        type: 'filter',\r
        },\r
        by_author: {\r
          type: 'foreign_filter',\r
            },\r
          },\r
        },\r
 -      play: {\r
 -        type: 'play',\r
 +    },\r
 +  },\r
 +  story: {\r
 +    lists: {\r
 +      public: {\r
 +        type: 'public',\r
 +      },\r
 +      private: {\r
 +        type: 'private',\r
 +      },\r
 +      by_comic: {\r
 +        type: 'through_filter',\r
 +        args: {\r
 +          through: 'comic_stories',\r
 +        },\r
 +      },\r
 +      by_sheet: {\r
 +        type: 'through_filter',\r
 +        args: {\r
 +          through: 'story_sheets',\r
 +        },\r
 +      },\r
 +      by_author: {\r
 +        type: 'filter',\r
        },\r
      },\r
    },\r
        by_speech_balloon: {\r
          type: 'filter',\r
        },\r
-       by_writing_format: {\r
-         type: 'filter',\r
-       },\r
        by_author: {\r
          type: 'foreign_filter',\r
          args: {\r
          'author',\r
        ],\r
        has_many: [\r
 +        'comic_stories.by_comic', \r
          'stories.by_comic', \r
        ],\r
      }, \r
    },\r
 -  story: {\r
 -    columns: {\r
 -      visible: {\r
 -        type: 'source',\r
 -      }, \r
 -    },\r
 +  comic_story: {\r
      column_names: [\r
        'comic_id', \r
 +      'story_id', \r
 +      't', \r
 +    ],\r
 +    associations: {\r
 +      belongs_to: [\r
 +        'comic', \r
 +        'story'\r
 +      ],\r
 +    }, \r
 +  },\r
 +  story: {\r
 +    column_names: [\r
        'title', \r
        'description', \r
        't', \r
      ],\r
      associations: {\r
        belongs_to: [\r
 -        'comic',\r
        ],\r
        has_many: [\r
 +        'comic_stories.by_story', \r
 +        'comics.by_story',\r
          'story_sheets.by_story', \r
          'sheets.by_story'\r
        ],\r
      }, \r
    },\r
    sheet: {\r
+     columns: {\r
+       visible: {\r
+         type: 'source',\r
+       }, \r
+     },\r
      column_names: [\r
        'caption', \r
        'width', \r
      }, \r
    },\r
    panel: {\r
+     columns: {\r
+       publish: {\r
+         type: 'source',\r
+       }, \r
+     },\r
      column_names: [\r
        'width', \r
        'height', \r
          'scrolls.by_author', \r
          'scroll_panels.by_author', \r
          'comics.by_author', \r
 +        'comic_stories.by_author', \r
          'stories.by_author', \r
          'sheets.by_author', \r
          'sheet_panels.by_author', \r
index bcc8df1,0000000..a17f2d8
mode 100644,000000..100644
--- /dev/null
@@@ -1,120 -1,0 +1,120 @@@
-         format.html { redirect_to play_comic_path(@comic) }
 +class ComicStoriesController < ApplicationController
 +  if Manifest.manifest.magic_numbers['run_mode'] == 0
 +    before_filter :authenticate_user, :only => [:new, :create, :edit, :update, :destroy]
 +    before_filter :authenticate_author, :only => [:new, :create, :edit, :update, :destroy]
 +  else
 +    before_filter :authenticate_reader, :only => [
 +      :index, :show, :by_story, :by_comic, :by_author, :count, :count_by_story, :count_by_comic, :count_by_author
 +    ]
 +    before_filter :authenticate_user, :only => [:new, :create, :edit, :update, :destroy]
 +    before_filter :authenticate_author, :only => [:new, :create, :edit, :update, :destroy]
 +  end
 +
 +  def self.model
 +    ComicStory
 +  end
 +  
 +  def index
 +    filer_list
 +  end
 +  
 +  def by_story
 +    filer_list
 +  end
 +  
 +  def by_comic
 +    filer_list
 +  end
 +  
 +  def by_author
 +    filer_list
 +  end
 +  
 +  def show
 +    set_show
 +    respond_to do |format|
 +      show_prof_format format
 +      format.json { render json: @item.comic_story_as_json(@operators.author) }
 +    end
 +  end
 +  
 +  def count
 +    list_count
 +  end
 +  
 +  def count_by_story
 +    list_count
 +  end
 +  
 +  def count_by_comic
 +    list_count
 +  end
 +  
 +  def count_by_author
 +    list_count
 +  end
 +  
 +  def new
 +    form_new
 +  end
 +  
 +  def edit
 +    form_edit
 +  end
 +  
 +  def create
 +    @comic_story = ComicStory.new 
 +    @comic_story.supply_default
 +    @comic_story.attributes = params[:comic_story]
 +    @comic_story.overwrite @operators
 +    @comic = Comic.edit(@comic_story.comic_id, @operators) if @comic_story.comic_id
 +    @story = Story.show(@comic_story.story_id, @operators) if @comic_story.story_id
 +    
 +    respond_to do |format|
 +      if @comic_story.store @operators
 +        flash[:notice] = I18n.t('flash.notice.created', :model => ComicStory.model_name.human)
-         format.html { redirect_to play_comic_path(@comic) }
++        format.html { redirect_to comic_path(@comic) }
 +        format.json { render json: @comic_story.comic_story_as_json(@operators.author) }
 +      else
 +        flash[:notice] = I18n.t('flash.notice.not_created', :model => ComicStory.model_name.human)
 +        format.html { render action: "new" }
 +        format.json { render json: @comic_story.errors, status: :unprocessable_entity }
 +      end
 +    end
 +  end
 +  
 +  def update
 +    @comic_story = ComicStory.edit(params[:id], @operators)
 +    ot = @comic_story.t
 +    @comic_story.attributes = params[:comic_story]
 +    @comic_story.overwrite @operators
 +    @comic = Comic.edit(@comic_story.comic_id, @operators) if @comic_story.comic_id
 +    respond_to do |format|
 +      if @comic_story.store @operators, ot
 +        flash[:notice] = I18n.t('flash.notice.updated', :model => ComicStory.model_name.human)
++        format.html { redirect_to comic_path(@comic) }
 +        format.json { head :ok }
 +      else
 +        flash[:notice] = I18n.t('flash.notice.not_updated', :model => ComicStory.model_name.human)
 +        format.html { render action: "edit" }
 +        format.json { render json: @comic_story.errors, status: :unprocessable_entity }
 +      end
 +    end
 +  end
 +
 +  def destroy
 +    @comic_story = ComicStory.edit(params[:id], @operators)
 +    @comic = Comic.edit(@comic_story.comic_id, @operators) if @comic_story.comic_id
 +    respond_to do |format|
 +      if @comic_story.destroy_and_shorten
 +        flash[:notice] = I18n.t('flash.notice.destroyed', :model => ComicStory.model_name.human)
 +        format.html { redirect_to play_comic_path(@comic) }
 +        format.json { head :ok }
 +      else
 +        flash[:notice] = I18n.t('flash.notice.not_destroyed', :model => ComicStory.model_name.human)
 +        format.html { redirect_to comic_story_path(@comic_story) }
 +        format.json { render json: @comic_story.errors, status: :unprocessable_entity }
 +      end
 +    end
 +  end
 +end
@@@ -3,7 -3,7 +3,7 @@@ class ComicsController < ApplicationCon
      before_filter :authenticate_user, :only => [:new, :create, :edit, :update, :destroy]
      before_filter :authenticate_author, :only => [:new, :create, :edit, :update, :destroy]
    else
 -    before_filter :authenticate_reader, :only => [:index, :show, :by_author, :count, :count_by_author]
 +    before_filter :authenticate_reader, :only => [:index, :show, :by_story, :by_author, :count, :count_by_story, :count_by_author]
      before_filter :authenticate_user, :only => [:new, :create, :edit, :update, :destroy]
      before_filter :authenticate_author, :only => [:new, :create, :edit, :update, :destroy]
    end
    def index
      filer_list
    end
 -
 +  
 +  def by_story
 +    filer_list
 +  end
 +  
    def by_author
      filer_list
    end
 -
 +  
    def show_html_format format
      format.html {
++      @comic = @item
++      action = Manifest.manifest.controllers['comics'].actions['play']
++      list = Locmare::ListGroup.list action.item_name, action.list_name
++      list_result = list.open(@operators, 
++        {:id => params[:id], :page => params[:page], :page_size => params[:page_size]}
++      )
++      @comic_stories = list_result.items 
++      if @operators.author
++        @new_story_items = assist_items('story', 'private')
++        #@new_story_filer = assist_filer 'story', @new_story_items
++      end
      }
    end
    
        format.rss 
      end
    end
 -
 +  
    def count
      list_count
    end
    
 +  def count_by_story
 +    list_count
 +  end
 +  
    def count_by_author
      list_count
    end
@@@ -33,6 -33,6 +33,7 @@@ class StoriesController < ApplicationCo
    def show_html_format format
      format.html {
        if @operators.author
++        @new_comic_items = assist_items('comic', 'private')
          @new_sheet_items = assist_items('sheet', 'private')
          #@new_sheet_filer = assist_filer 'sheet', @new_sheet_items
        end
    end
    
    def create
 -    @story = Story.new 
 -    @story.supply_default
 -    @story.attributes = params[:story]
 -    @story.overwrite
 -    @comic = Comic.edit(@story.comic_id, @operators) if @story.comic_id
 +    @story = Story.new
 +    @story.supply_default 
 +    jsn = nil
 +    if params[:json]
 +      jsn = JSON.parse_no_except(params[:json])
 +    end
 +    @prm = params[:story] || jsn
      
      respond_to do |format|
 -      if @story.store @operators
 +      if @story.store @prm, @operators
          flash[:notice] = I18n.t('flash.notice.created', :model => Story.model_name.human)
 -        format.html { redirect_to play_story_path(@story, :page => @story.t.to_i + 1) }
 -        format.json { render json: @story.to_json(Story.show_json_opt) }
 +        format.html { redirect_to @story }
 +        format.json { render json: @story.to_json(Story.show_json_opt), status: :created, location: @story }
        else
          flash[:notice] = I18n.t('flash.notice.not_created', :model => Story.model_name.human)
          format.html { render action: "new" }
    
    def update
      @story = Story.edit(params[:id], @operators)
 -    ot = @story.t
 -    @story.attributes = params[:story]
 -    @story.overwrite
 +    jsn = nil
 +    if params[:json]
 +      jsn = JSON.parse(params[:json])
 +    end
 +    @prm = params[:story] || jsn
      respond_to do |format|
 -      if @story.store @operators, ot
 +      if @story.store @prm, @operators
          flash[:notice] = I18n.t('flash.notice.updated', :model => Story.model_name.human)
 -        format.html { redirect_to play_story_path(@story, :page => @story.t.to_i + 1) }
 +        format.html { redirect_to @story }
          format.json { head :ok }
        else
          flash[:notice] = I18n.t('flash.notice.not_updated', :model => Story.model_name.human)
        end
      end
    end
 -
 +  
    def destroy
      @story = Story.edit(params[:id], @operators)
      respond_to do |format|
 -      if @story.destroy_and_shorten
 +      if @story.destroy_with_story_panel
          flash[:notice] = I18n.t('flash.notice.destroyed', :model => Story.model_name.human)
 -        format.html { redirect_to comic_path(@story.comic)}
 +        format.html { redirect_to '/home/stories' }
          format.json { head :ok }
        else
          flash[:notice] = I18n.t('flash.notice.not_destroyed', :model => Story.model_name.human)
 -        format.html { redirect_to story_path(@story) }
 +        format.html { redirect_to @story }
          format.json { render json: @story.errors, status: :unprocessable_entity }
        end
      end
    end
 +  
  end
index bcde23a,0000000..9e2fd28
mode 100644,000000..100644
--- /dev/null
@@@ -1,166 -1,0 +1,108 @@@
-   def self.new_t comic_id
-     r = Story.max_t(comic_id)
-     r.blank? ? 0 : r.to_i + 1
-   end
-   
-   def self.max_t comic_id
-     Story.maximum(:t, :conditions => ['comic_id = ?', comic_id])
-   end
-   
-   def self.find_t comic_id, t
-     Story.find(:first, :conditions => ['comic_id = ? and t = ?', comic_id, t])
-   end
-   
-   def self.collect_t story
-     r = Story.find(:all, :conditions => ['comic_id = ?', story.comic_id], :order => 't')
-     r.map {|s| s.t}
-   end
-   
-   def self.serial? ary
-     i = 0
-     ary.compact.sort.each do |t|
-       break false unless t == i
-       i += 1
-     end
-     ary.compact.size == i
-   end
-   
-   def self.validate_t story
-     Story.serial?(Story.collect_t(story))
-   end
-   
-   def insert_shift
-     Story.update_all('t = t + 1', ['comic_id = ? and t >= ?', self.comic_id, self.t])
-   end
-   
-   def lesser_shift old_t
-     self.t = 0 if self.t < 0
-     Story.update_all('t = t + 1', ['comic_id = ? and (t >= ? and t < ?)', self.comic_id, self.t, old_t])
-   end
-   
-   def higher_shift old_t
-     nf = Story.find_t(self.comic_id, self.t)
-     max_t = Story.max_t(self.comic_id).to_i
-     self.t = max_t if self.t > max_t
-     Story.update_all('t = t - 1', ['comic_id = ? and (t > ? and t <= ?)', self.comic_id, old_t, self.t])
-   end
-   
-   def update_shift old_t
-     if self.t > old_t
-       higher_shift old_t
-     else
-       lesser_shift old_t
-     end
-   end
-   
-   def rotate old_t = nil
-     if self.new_record?
-       if self.t.blank?
-         self.t = Story.new_t self.comic_id
-       else
-         self.insert_shift
-       end
-     else
-       if self.t.blank?
-       else
-         self.update_shift old_t
-       end
-     end
-   end
-   
 +class ComicStory < Peta::Leaf
 +  load_manifest
 +  belongs_to :author
 +  belongs_to :comic
 +  belongs_to :story
 +  
 +  validates :comic_id, :presence => true, :numericality => true, :existence => {:both => false}
 +  validates :story_id, :presence => true, :numericality => true, :existence => {:both => false}
 +  validates :author_id, :presence => true, :numericality => true, :existence => {:both => false}
 +  validates :t, :presence => true, :numericality => {:greater_than_or_equal_to => 0}
 +  
 +  def supply_default
 +    self.comic_id = nil
 +    self.story_id = nil
 +    self.t = nil
 +  end
 +  
 +  def overwrite operators
 +    return false unless operators.author
 +    self.author_id = operators.author.id
 +  end
 +  
++  def disp_t
++    self.t + 1
++  end
++  
++  def disp_t_by_text
++    I18n.t('comic_stories.show.t', :t => self.disp_t)
++  end
++  
++  def title
++    self.disp_t_by_text + ':' + self.story.title
++  end
++  
 +  def self.public_list_order
 +    'comic_stories.updated_at desc'
 +  end
 +  
 +  def self.list_where
 +    'comics.visible > 0'
 +  end
 +  
 +  def self.by_author_list_includes
 +    {
 +      :comic => {
 +        :author => {}
 +      }
 +    }
 +  end
 +  
 +  def self.play_list_where cid
 +    ['comic_stories.comic_id = ?', cid]
 +  end
 +  
 +  def self.play_list scroll, author, offset = 0, limit = ScrollPanel.default_panel_size
 +    ScrollPanel.where(self.play_list_where(scroll.id)).includes(ScrollPanel.list_opt).order('scroll_panels.t').offset(offset).limit(limit)
 +  end
 +  
 +  def self.list_opt
 +    {
 +      :comic => {
 +        :author => {}, 
 +      }
 +    }
 +  end
 +  
 +  def self.list_json_opt
 +    {:include => {
 +      :comic => {
 +        :author => {}, 
 +      }
 +    }}
 +  end
 +  
 +  def self.show_opt
 +    {:include => {
 +      :comic => {
 +      }
 +    }}
 +  end
 +  
-     self.comic.own?(operators) and self.comic.usable?(operators)
 +  def allow? operators
 +    return nil if self.story_id == nil or self.comic_id == nil
-     ScrollPanel.transaction do
++    self.comic.own?(operators) and self.story.own?(operators)
 +  end
 +  
 +  def store operators, old_t = nil
 +    res = false
-       res = ScrollPanel.validate_t(self.comic_id) 
++    self.class.transaction do
 +      case self.allow? operators
 +      when true
 +        self.rotate old_t
 +      when false
 +        raise ActiveRecord::Forbidden
 +      else
 +      end
 +      res = self.save
 +      raise ActiveRecord::Rollback unless res
++      res = self.class.validate_t(self.comic_id) 
 +      unless res
 +        self.errors.add :t, 'unserialized'
 +        raise ActiveRecord::Rollback 
 +      end
 +    end
 +    res
 +  end
 +  
 +end
@@@ -111,6 -111,76 +111,6 @@@ class ScrollPanel < Peta::Lea
      r
    end
    
 -  def self.new_t scroll_id
 -    r = ScrollPanel.max_t(scroll_id)
 -    r.blank? ? 0 : r.to_i + 1
 -  end
 -  
 -  def self.max_t scroll_id
 -    ScrollPanel.maximum(:t, :conditions => ['scroll_id = ?', scroll_id])
 -  end
 -  
 -  def self.find_t scroll_id, t
 -    ScrollPanel.find(:first, :conditions => ['scroll_id = ? and t = ?', scroll_id, t])
 -  end
 -  
 -  def self.collect_t scroll_panel
 -    r = ScrollPanel.find(:all, :conditions => ['scroll_id = ?', scroll_panel.scroll_id], :order => 't')
 -    r.map {|sp| sp.t}
 -  end
 -  
 -  def self.serial? ary
 -    i = 0
 -    ary.compact.sort.each do |t|
 -      break false unless t == i
 -      i += 1
 -    end
 -    ary.compact.size == i
 -  end
 -  
 -  def self.validate_t scroll_panel
 -    ScrollPanel.serial?(ScrollPanel.collect_t(scroll_panel))
 -  end
 -  
 -  def insert_shift
 -    ScrollPanel.update_all('t = t + 1', ['scroll_id = ? and t >= ?', self.scroll_id, self.t])
 -  end
 -  
 -  def lesser_shift old_t
 -    self.t = 0 if self.t < 0
 -    ScrollPanel.update_all('t = t + 1', ['scroll_id = ? and (t >= ? and t < ?)', self.scroll_id, self.t, old_t])
 -  end
 -  
 -  def higher_shift old_t
 -    nf = ScrollPanel.find_t(self.scroll_id, self.t)
 -    max_t = ScrollPanel.max_t(self.scroll_id).to_i
 -    self.t = max_t if self.t > max_t
 -    ScrollPanel.update_all('t = t - 1', ['scroll_id = ? and (t > ? and t <= ?)', self.scroll_id, old_t, self.t])
 -  end
 -  
 -  def update_shift old_t
 -    if self.t > old_t
 -      higher_shift old_t
 -    else
 -      lesser_shift old_t
 -    end
 -  end
 -  
 -  def rotate old_t = nil
 -    if self.new_record?
 -      if self.t.blank?
 -        self.t = ScrollPanel.new_t self.scroll_id
 -      else
 -        self.insert_shift
 -      end
 -    else
 -      if self.t.blank?
 -      else
 -        self.update_shift old_t
 -      end
 -    end
 -  end
 -  
    def allow? operators
      return nil if self.scroll_id == nil or self.panel_id == nil
      self.scroll.own?(operators) and self.panel.usable?(operators)
    
    def store operators, old_t = nil
      res = false
--    ScrollPanel.transaction do
++    self.class.transaction do
        case self.allow? operators
        when true
          self.rotate old_t
        end
        res = self.save
        raise ActiveRecord::Rollback unless res
-       res = ScrollPanel.validate_t(self.scroll_id) 
 -      res = ScrollPanel.validate_t(self) 
++      res = self.class.validate_t(self.scroll_id) 
        unless res
          self.errors.add :t, 'unserialized'
          raise ActiveRecord::Rollback 
      res
    end
    
 -  def destroy_and_shorten
 -    res = false
 -    ScrollPanel.transaction do
 -      ScrollPanel.update_all('t = t - 1', ['scroll_id = ? and (t > ?)', self.scroll_id, self.t])
 -      raise ActiveRecord::Rollback unless self.destroy
 -      res = true
 -    end
 -    res
 -  end
 -  
  end
@@@ -166,76 -166,76 +166,6 @@@ class SheetPanel < Peta::Elemen
      end
    end
    
--  def self.new_t sheet_id
--    r = SheetPanel.max_t(sheet_id)
--    r.blank? ? 0 : r.to_i + 1
--  end
--  
--  def self.max_t sheet_id
--    SheetPanel.maximum(:t, :conditions => ['sheet_id = ?', sheet_id])
--  end
--  
--  def self.find_t sheet_id, t
--    SheetPanel.find(:first, :conditions => ['sheet_id = ? and t = ?', sheet_id, t])
--  end
--  
--  def self.collect_t sheet_panel
--    r = SheetPanel.find(:all, :conditions => ['sheet_id = ?', sheet_panel.sheet_id], :order => 't')
--    r.map {|sp| sp.t}
--  end
--  
--  def self.serial? ary
--    i = 0
--    ary.compact.sort.each do |t|
--      break false unless t == i
--      i += 1
--    end
--    ary.compact.size == i
--  end
--  
--  def self.validate_t sheet_panel
--    SheetPanel.serial?(SheetPanel.collect_t(sheet_panel))
--  end
--  
--  def insert_shift
--    SheetPanel.update_all('t = t + 1', ['sheet_id = ? and t >= ?', self.sheet_id, self.t])
--  end
--  
--  def lesser_shift old_t
--    self.t = 0 if self.t < 0
--    SheetPanel.update_all('t = t + 1', ['sheet_id = ? and (t >= ? and t < ?)', self.sheet_id, self.t, old_t])
--  end
--  
--  def higher_shift old_t
--    nf = SheetPanel.find_t(self.sheet_id, self.t)
--    max_t = SheetPanel.max_t(self.sheet_id).to_i
--    self.t = max_t if self.t > max_t
--    SheetPanel.update_all('t = t - 1', ['sheet_id = ? and (t > ? and t <= ?)', self.sheet_id, old_t, self.t])
--  end
--  
--  def update_shift old_t
--    if self.t > old_t
--      higher_shift old_t
--    else
--      lesser_shift old_t
--    end
--  end
--  
--  def rotate old_t = nil
--    if self.new_record?
--      if self.t.blank?
--        self.t = SheetPanel.new_t self.sheet_id
--      else
--        self.insert_shift
--      end
--    else
--      if self.t.blank?
--      else
--        self.update_shift old_t
--      end
--    end
--  end
--  
    def allow? operators
      return nil if self.sheet_id == nil or self.panel_id == nil
      self.sheet.own?(operators) and self.panel.usable?(operators)
    
    def store operators, old_t = nil
      res = false
--    SheetPanel.transaction do
++    self.class.transaction do
        case self.allow? operators
        when true
          self.rotate old_t
        end
        res = self.save
        raise ActiveRecord::Rollback unless res
--      res = SheetPanel.validate_t(self
++      res = self.class.validate_t(self.sheet_id
        unless res
          self.errors.add :t, 'unserialized'
          raise ActiveRecord::Rollback 
      res
    end
    
--  def destroy_and_shorten
--    res = false
--    SheetPanel.transaction do
--      SheetPanel.update_all('t = t - 1', ['sheet_id = ? and (t > ?)', self.sheet_id, self.t])
--      raise ActiveRecord::Rollback unless self.destroy
--      res = true
--    end
--    res
--  end
--  
  end
@@@ -118,80 -118,80 +118,10 @@@ class StorySheet < Peta::Lea
      '[' + ary.map {|i| i.story_sheet_as_json(au) }.join(',') + ']'
    end
    
--  def self.new_t story_id
--    r = StorySheet.max_t(story_id)
--    r.blank? ? 0 : r.to_i + 1
--  end
--  
    def self.top_sheet story, author
      StorySheet.play_list(story, author).first
    end
    
--  def self.max_t story_id
--    StorySheet.maximum(:t, :conditions => ['story_id = ?', story_id])
--  end
--  
--  def self.find_t story_id, t
--    StorySheet.find(:first, :conditions => ['story_id = ? and t = ?', story_id, t])
--  end
--  
--  def self.collect_t story_sheet
--    r = StorySheet.find(:all, :conditions => ['story_id = ?', story_sheet.story_id], :order => 't')
--    r.map {|sp| sp.t}
--  end
--  
--  def self.serial? ary
--    i = 0
--    ary.compact.sort.each do |t|
--      break false unless t == i
--      i += 1
--    end
--    ary.compact.size == i
--  end
--  
--  def self.validate_t story_sheet
--    StorySheet.serial?(StorySheet.collect_t(story_sheet))
--  end
--  
--  def insert_shift
--    StorySheet.update_all('t = t + 1', ['story_id = ? and t >= ?', self.story_id, self.t])
--  end
--  
--  def lesser_shift old_t
--    self.t = 0 if self.t < 0
--    StorySheet.update_all('t = t + 1', ['story_id = ? and (t >= ? and t < ?)', self.story_id, self.t, old_t])
--  end
--  
--  def higher_shift old_t
--    nf = StorySheet.find_t(self.story_id, self.t)
--    max_t = StorySheet.max_t(self.story_id).to_i
--    self.t = max_t if self.t > max_t
--    StorySheet.update_all('t = t - 1', ['story_id = ? and (t > ? and t <= ?)', self.story_id, old_t, self.t])
--  end
--  
--  def update_shift old_t
--    if self.t > old_t
--      higher_shift old_t
--    else
--      lesser_shift old_t
--    end
--  end
--  
--  def rotate old_t = nil
--    if self.new_record?
--      if self.t.blank?
--        self.t = StorySheet.new_t self.story_id
--      else
--        self.insert_shift
--      end
--    else
--      if self.t.blank?
--      else
--        self.update_shift old_t
--      end
--    end
--  end
--  
    def allow? operators
      return nil if self.story_id == nil or self.sheet_id == nil
      self.story.own?(operators) and self.sheet.usable?(operators)
    
    def store operators, old_t = nil
      res = false
--    StorySheet.transaction do
++    self.class.transaction do
        case self.allow? operators
        when true
          self.rotate old_t
        end
        res = self.save
        raise ActiveRecord::Rollback unless res
--      res = StorySheet.validate_t(self
++      res = self.class.validate_t(self.story_id
        unless res
          self.errors.add :t, 'unserialized'
          raise ActiveRecord::Rollback 
      res
    end
    
--  def destroy_and_shorten
--    res = false
--    StorySheet.transaction do
--      StorySheet.update_all('t = t - 1', ['story_id = ? and (t > ?)', self.story_id, self.t])
--      raise ActiveRecord::Rollback unless self.destroy
--      res = true
--    end
--    res
--  end
--  
  end
index 0000000,0000000..13d9af1
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,32 @@@
++<tr>
++  <td>
++    <%= link_to comic_icon(:object => comic, :size => 25), comic_path(comic) %>
++    <%= link_to h(truncate(comic.title, :length => 40)), play_comic_path(comic) %>
++    (<%= comic.comic_stories.size -%>)
++  </td>
++  <td>
++    <%= distance_of_time_in_words_to_now comic.updated_at %>
++  </td>
++  <td>
++    <%= link_to author_icon(:object => comic.author, :size => 25), author_path(comic.author) %>
++    <%= link_to h(truncate(comic.author.name, :length => 12)), author_path(comic.author) %>
++  </td>
++  <td>
++    <% if comic.own? operators %>
++      <% @comic_story = ComicStory.new :comic_id => comic.id, :story_id => story.id %>
++      <%= form_for(@comic_story) do |f| %>
++        <%= f.hidden_field :comic_id %>
++        <%= f.hidden_field :t %>
++        <%= f.hidden_field :story_id %>
++        <div class="actions">
++          <%= f.submit t('comic_stories.append.comic') %>
++        </div>
++      <% end %>
++    <% end %>
++  </td>
++</tr>
++<tr>
++  <td colspan="4">
++    <%= h(truncate(comic.description, :length => 40)) %>
++  </td>
++</tr>
index 0000000,0000000..8ce83b7
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,21 @@@
++<tr>
++  <td>
++    <%= link_to story_icon(:object => story, :size => 25), story_path(story) %>
++    <%= link_to author_icon(:object => story.author, :size => 17), author_path(story.author) %>
++  </td>
++  <td>
++    <%= link_to h(truncate(h(story.title), :length => 40)), story_path(story) %>
++  </td>
++  <td>
++    <%= l story.updated_at %>
++  </td>
++  <td>
++    <% @comic_story = ComicStory.new :comic_id => comic.id, :story_id => story.id -%>
++    <%= form_for(@comic_story) do |f| %>
++      <%= f.hidden_field :comic_id %>
++      <%= f.hidden_field :t %>
++      <%= f.hidden_field :story_id %>
++      <%= f.submit t('comic_stories.append.story') %>
++    <% end %>
++  </td>
++</tr>
@@@ -1,54 -1,54 +1,39 @@@
  <% @page_title = t('.title') + ':' + @item.title %>
--<h1><%= t('.title') %></h1>
--<p id="notice"><%= notice %></p>
--
++<h1><%= @item.title %></h1>
  <p>
--  <b><%= t_m 'Comic.title' -%>:</b>
--  <%= link_to h(@item.title), comic_path(@item) %>
++  <b><%= t_m 'Comic.author_id' -%>:</b>
++  <%= link_to h(@item.author.name), author_path(@item.author) %>
++  <b><%= t_m 'Comic.updated_at' -%>:</b>
++  <%= l @item.updated_at %>
  </p>
  
++<p id="notice"><%= notice %></p>
++
  <p>
    <b><%= t_m 'Comic.description' -%>:</b>
    <%= h(@item.description) %>
  </p>
  
--<p>
--  <b><%= t_m 'Comic.visible' -%>:</b>
--  <%= t_selected_item('comic_visible_items', @item.visible) %>
--</p>
--
--<p>
--  <b><%= t_m 'Comic.author_id' -%>:</b>
--  <%= link_to h(@item.author.name), author_path(@item.author) %>
--</p>
--
--<% @item.stories.each do |story| %>
--  <% if story.visible? @operators -%>
--    <div>
--      <%= link_to t('stories.show.t', :t => story.disp_t), story_path(story) %>
--      <%= link_to h(story.title), play_story_path(story) %>
--    </div>
++<div>
++  <% @comic_stories.each do |comic_story| %>
++    <% if comic_story.story -%>
++      <%= link_to comic_story.title, play_story_path(comic_story.story) %>
++    <% end %>
    <% end %>
--<% end %>
--<p>
--  <b><%= t_m 'Comic.created_at' -%>:</b>
--  <%= l @item.created_at %>
--</p>
++</div>
  
++<% if @item.own? @operators -%>
  <p>
--  <b><%= t_m 'Comic.updated_at' -%>:</b>
--  <%= l @item.updated_at %>
++  <b><%= t_m 'Comic.visible' -%>:</b>
++  <%= t_selected_item('comic_visible_items', @item.visible) %>
  </p>
  
--<% if @item.own? @operators -%>
    <%= link_to t('link.edit'), edit_comic_path(@item) %>
    <%= link_to t('link.destroy'), comic_path(@item), :method => :delete %>
--
--  <h2>
--    <%= t('stories.index.new') %>
--  </h2>
--  <% @story = Story.new -%>
--  <% @story.supply_default -%>
--  <% @story.attributes = {:comic_id => @item.id} -%>
--  <%= render 'stories/form' %>
++  <h3><%= t('comic_stories.append.new_stories') -%></h3>
++  <table>
++    <% @new_story_items.each do |story| %>
++      <%= render 'comic_stories/append_story', :story => story, :comic => @item, :operators => @operators %>
++    <% end %>
++  </table>
  <% end %>
@@@ -12,7 -12,7 +12,7 @@@
  <% else %>
    <h2><%= t('stories.play.empty') %></h2>
  <% end %>
--<%= render 'stories/play_footer', :story => @item, :operators => @operators %>
++<%# render 'stories/play_footer', :story => @item, :operators => @operators %>
  
  <% if @item.own? @operators -%>
    <h3><%= t('story_sheets.append.new_sheets') -%></h3>
@@@ -1,8 -1,14 +1,8 @@@
  <h1><%= t('.title') %></h1>
  <p id="notice"><%= notice %></p>
  
 -<p>
 -  <b><%= t_m 'Story.comic_id' -%>:</b>
 -  <%= link_to comic_icon(:object => @item.comic), comic_path(@item.comic) %>
 -  <%= link_to h(@item.comic.title), comic_path(@item.comic) %>
 -</p>
 -
  <div>
 -  <%= link_to t('stories.show.t', :t => @item.disp_t), story_path(@item) %>
 +  <%= link_to @item.title, story_path(@item) %>
    <%= link_to_if @item, h(@item.title), play_story_path(@item) %>
  </div>
  
    <%= link_to t('link.edit'), edit_story_path(@item) %>
    <%= link_to t('link.destroy'), story_path(@item), :method => :delete %>
  
++  <h3><%= t('comic_stories.append.new_comics') -%></h3>
++  <table>
++    <% @new_comic_items.each do |comic| %>
++      <%= render 'comic_stories/append_comic', :story => @item, :comic => comic, :operators => @operators %>
++    <% end %>
++  </table>
++
    <h3><%= t('story_sheets.append.new_sheets') -%></h3>
    <table>
      <% @new_sheet_items.each do |sheet| %>
@@@ -22,7 -22,6 +22,7 @@@ ja
        scroll: スクロール
        scroll_panel: スクコマ
        comic: コミック
 +      comic_story: コミスト
        story: ストーリー
        story_sheet: スト紙
        sheet: 用紙
@@@ -99,6 -98,7 +99,6 @@@
        scroll_panel:
          scroll_id: スクロール
          panel_id: コマ
 -        author_id: 編集者
          t: No.
          created_at: 作成
          updated_at: 更新
          author_id: 作家
          created_at: 更新
          updated_at: 作成
 +      comic_story:
 +        comic_id: コミック
 +        story_id: ストーリー
 +        t: No.
 +        created_at: 作成
 +        updated_at: 更新
        story:
          comic_id: コミック
          title: タイトル
        story_sheet:
          story_id: ストーリー
          sheet_id: 用紙
 -        author_id: 編集者
          t: No.
          created_at: 作成
          updated_at: 更新
        title: 最近更新したスクコマ
      comics:
        title: 最近更新したコミック
 +    comic_stories:
 +      title: 最近更新したコミスト
      stories:
        title: 最近更新したストーリー
      story_sheets:
      submit:
        new: コミック作成
        edit: コミック変更
 +  comic_stories:
 +    index:
 +      title: コミスト一覧
 +    by_comic:
 +      title: コミックのコミスト一覧
 +    by_story:
 +      title: ストーリーのコミスト一覧
 +    by_author:
 +      title: 作家のコミスト一覧
 +    show:
 +      title: コミスト詳細
++      t: 第%{t}話
 +    new:
 +      title: コミスト追加
 +    edit:
 +      title: 並び替え
 +    create:
 +      title: コミスト追加
 +    update:
 +      title: 並び替え
 +    destroy:
 +      title: コミスト削除
 +    submit:
 +      new: コミスト作成
 +      edit: コミスト変更
 +    move: 移動
 +    append:
 +      story: このストーリーを追加する
 +      comic: このコミックに追加する
 +      new_stories: 最近作成したストーリー
 +      new_comics: 最近作成したコミック
 +      fresh_comics: 最近更新したコミック
    stories:
      story_sheets_count: '%{c}P'
      index:
        new: 新ストーリー
      show:
        title: ストーリー詳細
--      t: 第%{t}話
      play:
        title: ストーリーを読む
        empty: 用紙はありません
        to_scrolls: 最近更新したスクロール
        to_scroll_panels: 最近更新したスクコマ
        to_comics: 最近更新したコミック
 +      to_comic_stories: 最近更新したコミスト
        to_stories: 最近更新したストーリー
        to_story_sheets: 最近更新したスト紙
        to_sheets: 最近更新した用紙
diff --combined config/routes.rb
@@@ -40,8 -40,12 +40,8 @@@ Pettanr::Application.routes.draw d
        post :create
      end
      member do
 -      get :scroll_panels
 -      get :panels
        get :by_author
        get :by_panel
 -      get :scroll_panels_count
 -      get :panels_count
        get :count_by_author
        get :count_by_panel
        get :play
@@@ -58,7 -62,6 +58,7 @@@
      collection do
        get :index
        get :show
 +      get :count
        post :create
      end
      member do
        post :create
      end
      member do
 -      get :stories
        get :by_author
 -      get :by_me
 -      get :stories_count
 +      get :by_story
        get :count_by_author
 -      get :count_by_me
 +      get :count_by_story
        get :play
        get :edit
        put :update
        delete :destroy
      end
    end
 +  resources :comic_stories do
 +    new do
 +      get :new
 +    end
 +    collection do
 +      get :index
 +      get :show
 +      get :count
 +      post :create
 +    end
 +    member do
 +      get :by_comic
 +      get :by_story
 +      get :by_author
 +      get :count_by_comic
 +      get :count_by_story
 +      get :count_by_author
 +      get :edit
 +      put :update
 +      delete :destroy
 +    end
 +  end
    resources :stories do
      new do
        get :new
      collection do
        get :index
        get :show
 +      get :count
        post :create
      end
      member do
 -      get :story_sheets
 -      get :sheets
        get :by_comic
        get :by_sheet
        get :by_author
 -      get :story_sheets_count
 -      get :sheets_count
        get :count_by_comic
        get :count_by_sheet
        get :count_by_author
      collection do
        get :index
        get :show
 +      get :count
        post :create
      end
      member do
      collection do
        get :index
        get :show
 +      get :count
        post :create
      end
      member do
      collection do
        get :index
        get :show
 +      get :count
        post :create
      end
      member do
      collection do
        get :index
        get :show
 +      get :count
        get :credit
        get :search
        get :list
      collection do
        get :index
        get :show
 +      get :count
        get :new
        post :create
        get :count
      collection do
        get :index
        get :show
 +      get :count
      end
      member do
        get :speech_balloons
      collection do
        get :index
        get :show
 +      get :count
      end
      member do
        get :speeches
      collection do
        get :index
        get :show
 +      get :count
      end
      member do
        get :licenses
        post :create
      end
      member do
-       get :scrolls
-       get :scroll_panels
-       get :comics
-       get :comic_stories
-       get :stories
-       get :story_sheets
-       get :sheets
-       get :sheet_panels
-       get :panels
-       get :panel_pictures
-       get :speech_balloons
-       get :ground_pictures
-       get :ground_colors
-       get :scrolls_count
-       get :scroll_panels_count
-       get :comics_count
-       get :stories_count
-       get :story_sheets_count
-       get :sheets_count
-       get :sheet_panels_count
-       get :panels_count
-       get :panel_pictures_count
-       get :speech_balloons_count
-       get :ground_pictures_count
-       get :ground_colors_count
        get :edit
        put :update
        delete :destroy
        post :create
      end
      member do
-       get :resource_pictures
-       get :resource_pictures_count
        get :edit
        put :update
        delete :destroy
      collection do
        get :index
        get :show
 +      get :count
      end
      member do
        #get :balloons
          },\r
          "by_author": {\r
            "type": "filter"\r
 +        },\r
 +        "by_story": {\r
 +          "type": "through_filter",\r
 +          "args": {\r
 +            "through": "comic_stories"\r
 +          }\r
          }\r
        }\r
      },\r
 -    "story": {\r
 +    "comic_story": {\r
        "lists": {\r
          "public": {\r
            "type": "public"\r
          "private": {\r
            "type": "private"\r
          },\r
 +        "play": {\r
 +          "type": "play",\r
 +          "args": {\r
 +            "filter_item_name": "comic",\r
 +            "filter_model_name": "comic_story",\r
 +            "filter_key": "comic_id"\r
 +          }\r
 +        },\r
          "by_comic": {\r
            "type": "filter"\r
          },\r
 -        "by_sheet": {\r
 -          "type": "through_filter",\r
 -          "args": {\r
 -            "through": "story_sheets"\r
 -          }\r
 +        "by_story": {\r
 +          "type": "filter"\r
          },\r
          "by_author": {\r
            "type": "foreign_filter",\r
                "type": "method"\r
              }\r
            }\r
 +        }\r
 +      }\r
 +    },\r
 +    "story": {\r
 +      "lists": {\r
 +        "public": {\r
 +          "type": "public"\r
          },\r
 -        "play": {\r
 -          "type": "play"\r
 +        "private": {\r
 +          "type": "private"\r
 +        },\r
 +        "by_comic": {\r
 +          "type": "through_filter",\r
 +          "args": {\r
 +            "through": "comic_stories"\r
 +          }\r
 +        },\r
 +        "by_sheet": {\r
 +          "type": "through_filter",\r
 +          "args": {\r
 +            "through": "story_sheets"\r
 +          }\r
 +        },\r
 +        "by_author": {\r
 +          "type": "filter"\r
          }\r
        }\r
      },\r
          "by_speech_balloon": {\r
            "type": "filter"\r
          },\r
--        "by_writing_format": {\r
--          "type": "filter"\r
--        },\r
          "by_author": {\r
            "type": "foreign_filter",\r
            "args": {\r
            "author"\r
          ],\r
          "has_many": [\r
 +          "comic_stories.by_comic",\r
            "stories.by_comic"\r
          ]\r
        }\r
      },\r
 -    "story": {\r
 +    "comic_story": {\r
        "column_names": [\r
          "comic_id",\r
 +        "story_id",\r
 +        "t"\r
 +      ],\r
 +      "associations": {\r
 +        "belongs_to": [\r
 +          "comic",\r
 +          "story"\r
 +        ]\r
 +      }\r
 +    },\r
 +    "story": {\r
 +      "column_names": [\r
          "title",\r
          "description",\r
          "t",\r
          "visible"\r
        ],\r
        "associations": {\r
 -        "belongs_to": [\r
 -          "comic"\r
 -        ],\r
 +        "belongs_to": [],\r
          "has_many": [\r
 +          "comic_stories.by_story",\r
 +          "comics.by_story",\r
            "story_sheets.by_story",\r
            "sheets.by_story"\r
          ]\r
        }\r
      },\r
      "sheet": {\r
++      "columns": {\r
++        "visible": {\r
++          "type": "source"\r
++        }\r
++      },\r
        "column_names": [\r
          "caption",\r
          "width",\r
        }\r
      },\r
      "panel": {\r
++      "columns": {\r
++        "publish": {\r
++          "type": "source"\r
++        }\r
++      },\r
        "column_names": [\r
          "width",\r
          "height",\r
            "scrolls.by_author",\r
            "scroll_panels.by_author",\r
            "comics.by_author",\r
 +          "comic_stories.by_author",\r
            "stories.by_author",\r
            "sheets.by_author",\r
            "sheet_panels.by_author",\r
        "summary": {},\r
        "edit": {}\r
      },\r
 +    "comic_story": {\r
 +      "symbol": {\r
 +        "type": "default",\r
 +        "args": {\r
 +          "link": {\r
 +            "type": "none"\r
 +          }\r
 +        }\r
 +      },\r
 +      "caption": {\r
 +        "type": "none"\r
 +      },\r
 +      "summary": {},\r
 +      "edit": {\r
 +        "type": "none"\r
 +      }\r
 +    },\r
      "story": {\r
        "symbol": {},\r
        "caption": {\r
          "type": "default",\r
          "args": {\r
            "face": {\r
 -            "type": "method",\r
 +            "type": "column",\r
              "args": {\r
 -              "method_name": "title_with_t"\r
 +              "column_name": "title"\r
              }\r
            },\r
            "link": {\r
          "author_id"\r
        ]\r
      },\r
 -    "story": {\r
 +    "comic_story": {\r
        "fields": {\r
          "comic_id": {\r
 +          "tag": {\r
 +            "type": "number"\r
 +          }\r
 +        },\r
 +        "story_id": {\r
 +          "tag": {\r
 +            "type": "number"\r
 +          }\r
 +        },\r
 +        "t": {\r
 +          "tag": {\r
 +            "type": "number"\r
 +          }\r
 +        },\r
 +        "id": {\r
            "label": {\r
              "type": "none"\r
            },\r
            "tag": {\r
              "type": "hidden"\r
            }\r
 -        },\r
 +        }\r
 +      },\r
 +      "field_names": [\r
 +        "comic_id",\r
 +        "story_id",\r
 +        "t",\r
 +        "id"\r
 +      ]\r
 +    },\r
 +    "story": {\r
 +      "fields": {\r
          "title": {\r
            "label": {\r
              "args": {\r
            },\r
            "row_break": true\r
          },\r
 -        "t": {\r
 -          "tag": {\r
 -            "type": "number"\r
 -          }\r
 -        },\r
          "id": {\r
            "label": {\r
              "type": "none"\r
          }\r
        },\r
        "field_names": [\r
 -        "comic_id",\r
          "title",\r
          "description",\r
          "visible",\r
 -        "t",\r
          "id",\r
          "author_id"\r
        ]\r
diff --combined public/manifest.json
        "type": "binder",\r
        "args": {}\r
      },\r
 +    "comic_story": {\r
 +      "type": "leaf",\r
 +      "args": {\r
 +        "parent_model_name": "comic"\r
 +      }\r
 +    },\r
      "story": {\r
        "type": "binder",\r
        "args": {}\r
              "list_name": "public"\r
            }\r
          },\r
 +        "by_story": {\r
 +          "type": "list"\r
 +        },\r
          "by_author": {\r
            "type": "list"\r
          },\r
++        "play": {\r
++          "type": "list",\r
++          "args": {\r
++            "item_name": "comic_story",\r
++            "list_name": "play"\r
++          }\r
++        },\r
          "show": {\r
            "type": "show"\r
          },\r
              "list_name": "public"\r
            }\r
          },\r
 +        "count_by_story": {\r
 +          "type": "count"\r
 +        },\r
          "count_by_author": {\r
            "type": "count"\r
          },\r
          }\r
        }\r
      },\r
 -    "stories": {\r
 +    "comic_stories": {\r
        "actions": {\r
          "index": {\r
            "type": "list",\r
            }\r
          },\r
          "by_comic": {\r
 +          "type": "list"\r
 +        },\r
 +        "by_story": {\r
 +          "type": "list"\r
 +        },\r
 +        "by_author": {\r
 +          "type": "list"\r
 +        },\r
 +        "show": {\r
 +          "type": "show"\r
 +        },\r
 +        "count": {\r
 +          "type": "count",\r
 +          "args": {\r
 +            "list_name": "public"\r
 +          }\r
 +        },\r
 +        "count_by_comic": {\r
            "type": "count"\r
          },\r
 -        "by_sheet": {\r
 +        "count_by_story": {\r
 +          "type": "count"\r
 +        },\r
 +        "count_by_author": {\r
            "type": "count"\r
          },\r
 +        "new": {\r
 +          "type": "new"\r
 +        },\r
 +        "edit": {\r
 +          "type": "edit"\r
 +        }\r
 +      }\r
 +    },\r
 +    "stories": {\r
 +      "actions": {\r
 +        "index": {\r
 +          "type": "list",\r
 +          "args": {\r
 +            "list_name": "public"\r
 +          }\r
 +        },\r
 +        "by_comic": {\r
 +          "type": "list"\r
 +        },\r
 +        "by_sheet": {\r
 +          "type": "list"\r
 +        },\r
          "by_author": {\r
            "type": "list"\r
          },\r
              "list_name": "public"\r
            }\r
          },\r
 +        "count_by_comic": {\r
 +          "type": "count"\r
 +        },\r
 +        "count_by_sheet": {\r
 +          "type": "count"\r
 +        },\r
          "count_by_author": {\r
            "type": "count"\r
          },\r
              "list_name": "public"\r
            }\r
          },\r
--        "scrolls": {\r
--          "type": "list",\r
--          "args": {\r
--            "list_name": "scrolls"\r
--          }\r
--        },\r
--        "comics": {\r
--          "type": "list",\r
--          "args": {\r
--            "list_name": "comics"\r
--          }\r
--        },\r
--        "stories": {\r
--          "type": "list",\r
--          "args": {\r
--            "list_name": "stories"\r
--          }\r
--        },\r
--        "sheets": {\r
--          "type": "list",\r
--          "args": {\r
--            "list_name": "sheets"\r
--          }\r
--        },\r
--        "panels": {\r
--          "type": "list",\r
--          "args": {\r
--            "list_name": "panels"\r
--          }\r
--        },\r
--        "panel_pictures": {\r
--          "type": "list",\r
--          "args": {\r
--            "list_name": "panel_pictures"\r
--          }\r
--        },\r
--        "speech_balloons": {\r
--          "type": "list",\r
--          "args": {\r
--            "list_name": "speech_balloons"\r
--          }\r
--        },\r
--        "ground_pictures": {\r
--          "type": "list",\r
--          "args": {\r
--            "list_name": "ground_pictures"\r
--          }\r
--        },\r
--        "ground_colors": {\r
--          "type": "list",\r
--          "args": {\r
--            "list_name": "ground_colors"\r
--          }\r
--        },\r
          "show": {\r
            "type": "show"\r
          },\r
              "list_name": "public"\r
            }\r
          },\r
--        "resource_pictures": {\r
--          "type": "list",\r
--          "args": {\r
--            "list_name": "resource_pictures"\r
--          }\r
--        },\r
          "show": {\r
            "type": "show"\r
          },\r
          "has_many": {\r
            "scroll_panels": {},\r
            "panels": {\r
 -            "through": "scroll_panel"\r
 +            "through": "scroll_panels"\r
            }\r
          }\r
        },\r
            "author": {}\r
          },\r
          "has_many": {\r
 -          "stories": {}\r
 +          "comic_stories": {},\r
 +          "stories": {\r
 +            "through": "comic_stories"\r
 +          }\r
          }\r
        },\r
        "attributes": {\r
          }\r
        }\r
      },\r
 -    "story": {\r
 +    "comic_story": {\r
        "associations": {\r
          "belongs_to": {\r
 -          "comic": {}\r
 +          "comic": {},\r
 +          "story": {}\r
          },\r
 -        "has_many": {\r
 -          "story_sheets": {},\r
 -          "sheets": {\r
 -            "through": "story_sheets"\r
 -          }\r
 -        }\r
 +        "has_many": {}\r
        },\r
        "attributes": {\r
          "comic_id": {\r
            "type": "number",\r
            "rules": {\r
 +            "required": true,\r
 +            "number": true\r
 +          }\r
 +        },\r
 +        "story_id": {\r
 +          "type": "number",\r
 +          "rules": {\r
 +            "required": true,\r
              "number": true\r
            }\r
          },\r
 +        "t": {\r
 +          "type": "number",\r
 +          "rules": {\r
 +            "required": true,\r
 +            "number": true,\r
 +            "min": 0\r
 +          }\r
 +        },\r
 +        "author_id": {\r
 +          "type": "number",\r
 +          "rules": {\r
 +            "required": true,\r
 +            "number": true\r
 +          }\r
 +        }\r
 +      }\r
 +    },\r
 +    "story": {\r
 +      "associations": {\r
 +        "belongs_to": {},\r
 +        "has_many": {\r
 +          "comic_stories": {},\r
 +          "comics": {\r
 +            "through": "comic_stories"\r
 +          },\r
 +          "story_sheets": {},\r
 +          "sheets": {\r
 +            "through": "story_sheets"\r
 +          }\r
 +        }\r
 +      },\r
 +      "attributes": {\r
          "title": {\r
            "type": "text",\r
            "rules": {}\r
                "select_item_name": "story_visible_items"\r
              }\r
            }\r
 +        },\r
 +        "author_id": {\r
 +          "type": "number",\r
 +          "rules": {\r
 +            "required": true,\r
 +            "number": true\r
 +          }\r
          }\r
        }\r
      },\r