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)
46 files changed:
app/assets/images/comic_story.gif [new file with mode: 0644]
app/assets/javascripts/comic_stories.js.coffee [new file with mode: 0644]
app/assets/javascripts/manifest/work/controllers.js.coffee.erb
app/assets/javascripts/manifest/work/filers.js.coffee.erb
app/assets/javascripts/manifest/work/forms.js.coffee.erb
app/assets/javascripts/manifest/work/items.js.coffee.erb
app/assets/javascripts/manifest/work/list_groups.js.coffee.erb
app/assets/javascripts/manifest/work/models.js.coffee.erb
app/assets/javascripts/manifest/work/profilers.js.coffee.erb
app/assets/stylesheets/comic_stories.css.scss [new file with mode: 0644]
app/controllers/comic_stories_controller.rb [new file with mode: 0644]
app/controllers/comics_controller.rb
app/controllers/sheets_controller.rb
app/controllers/stories_controller.rb
app/helpers/comic_stories_helper.rb [new file with mode: 0644]
app/models/comic.rb
app/models/comic_story.rb [new file with mode: 0644]
app/models/folder.rb
app/models/panel_picture.rb
app/models/scroll_panel.rb
app/models/sheet_panel.rb
app/models/story.rb
app/models/story_sheet.rb
app/views/comic_stories/_append_comic.html.erb [new file with mode: 0644]
app/views/comic_stories/_append_story.html.erb [new file with mode: 0644]
app/views/comic_stories/_form.html.erb [new file with mode: 0644]
app/views/comic_stories/_order.html.erb [new file with mode: 0644]
app/views/comic_stories/_summary.html.erb [new file with mode: 0644]
app/views/comic_stories/edit.html.erb [new file with mode: 0644]
app/views/comic_stories/new.html.erb [new file with mode: 0644]
app/views/comics/_summary.html.erb
app/views/comics/show.html.erb
app/views/stories/_summary.html.erb
app/views/stories/play.html.erb
app/views/stories/show.html.erb
config/locales/pettanr.ja.yml
config/routes.rb
db/migrate/20140519235843_create_comic_stories.rb [new file with mode: 0644]
db/migrate/20140520102407_rm_comic_id_on_story.rb [new file with mode: 0644]
lib/peta/leaf.rb
public/images/comic_story.gif [new file with mode: 0644]
public/local_manifest.json
public/manifest.json
spec/controllers/comic_stories_controller_spec.rb [new file with mode: 0644]
spec/helpers/comic_stories_helper_spec.rb [new file with mode: 0644]
spec/models/comic_story_spec.rb [new file with mode: 0644]

diff --git a/app/assets/images/comic_story.gif b/app/assets/images/comic_story.gif
new file mode 100644 (file)
index 0000000..0707502
Binary files /dev/null and b/app/assets/images/comic_story.gif differ
diff --git a/app/assets/javascripts/comic_stories.js.coffee b/app/assets/javascripts/comic_stories.js.coffee
new file mode 100644 (file)
index 0000000..7615679
--- /dev/null
@@ -0,0 +1,3 @@
+# Place all the behaviors and hooks related to the matching controller here.
+# All this logic will automatically be available in application.js.
+# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
index 0fd0c17..f8b16d6 100644 (file)
           \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
+      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
+      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
+      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
index 2ac275d..c10123b 100644 (file)
     edit: {\r
     },\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
+    },\r
+    edit: {\r
+      type: 'none',\r
+    },\r
+  },\r
   story: {\r
     symbol: {\r
     },\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
index 89561e5..db99caf 100644 (file)
       '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
           type: 'hidden',\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
index 7148036..60c6351 100644 (file)
     args: {\r
     },\r
   },\r
+  comic_story: {\r
+    type: 'leaf',\r
+    args: {\r
+      parent_model_name: 'comic',\r
+    },\r
+  },\r
   story: {\r
     type: 'binder',\r
     args: {\r
index af2913f..422aa3f 100644 (file)
       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
index 58cdd7f..cb668d8 100644 (file)
@@ -74,7 +74,7 @@
         scroll_panels: {\r
         }, \r
         panels: {\r
-          through: 'scroll_panel',\r
+          through: 'scroll_panels',\r
         }, \r
       },\r
     },\r
         }, \r
       },\r
       has_many: {\r
+        comic_stories: {\r
+        }, \r
         stories: {\r
+          through: 'comic_stories',\r
         }, \r
       },\r
     },\r
       },\r
     },\r
   },\r
-  story: {\r
+  comic_story: {\r
     associations: {\r
       belongs_to: {\r
         comic: {\r
         }, \r
+        story: {\r
+        }, \r
       },\r
       has_many: {\r
-        story_sheets: {\r
-        }, \r
-        sheets: {\r
-          through: 'story_sheets',\r
-        }, \r
       },\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
+      },\r
+      has_many: {\r
+        comic_stories: {\r
+        }, \r
+        comics: {\r
+          through: 'comic_stories',\r
+        }, \r
+        story_sheets: {\r
+        }, \r
+        sheets: {\r
+          through: 'story_sheets',\r
+        }, \r
+      },\r
+    },\r
+    attributes: {\r
       title: {\r
         type: 'text',\r
         rules : {\r
           },\r
         },\r
       },\r
+      author_id: {\r
+        type: 'number',\r
+        rules : {\r
+          required: true,\r
+          number: true,\r
+        }\r
+      },\r
     },\r
   },\r
   story_sheet: {\r
index 2ce9998..59cfe3a 100644 (file)
         '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
         '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
diff --git a/app/assets/stylesheets/comic_stories.css.scss b/app/assets/stylesheets/comic_stories.css.scss
new file mode 100644 (file)
index 0000000..ee7577e
--- /dev/null
@@ -0,0 +1,3 @@
+// Place all the styles related to the comic_stories controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/
diff --git a/app/controllers/comic_stories_controller.rb b/app/controllers/comic_stories_controller.rb
new file mode 100644 (file)
index 0000000..a17f2d8
--- /dev/null
@@ -0,0 +1,120 @@
+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 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
index 5a5312b..587cc10 100644 (file)
@@ -3,7 +3,7 @@ class ComicsController < ApplicationController
     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
@@ -15,13 +15,28 @@ class ComicsController < ApplicationController
   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
   
@@ -35,11 +50,15 @@ class ComicsController < ApplicationController
       format.rss 
     end
   end
-
+  
   def count
     list_count
   end
   
+  def count_by_story
+    list_count
+  end
+  
   def count_by_author
     list_count
   end
index 2f24813..0141b20 100644 (file)
@@ -103,7 +103,7 @@ class SheetsController < ApplicationController
       jsn = JSON.parse_no_except(params[:json])
     end
     @prm = params[:sheet] || jsn
-
+    
     respond_to do |format|
       if @sheet.store @prm, @operators
         flash[:notice] = I18n.t('flash.notice.created', :model => Sheet.model_name.human)
@@ -116,7 +116,7 @@ class SheetsController < ApplicationController
       end
     end
   end
-
+  
   def update
     @sheet = Sheet.edit(params[:id], @operators)
     jsn = nil
@@ -136,7 +136,7 @@ class SheetsController < ApplicationController
       end
     end
   end
-
+  
   def destroy
     @sheet = Sheet.edit(params[:id], @operators)
     respond_to do |format|
index 0765171..5977fe4 100644 (file)
@@ -33,6 +33,7 @@ class StoriesController < ApplicationController
   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
@@ -99,17 +100,19 @@ class StoriesController < ApplicationController
   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" }
@@ -120,13 +123,15 @@ class StoriesController < ApplicationController
   
   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)
@@ -135,19 +140,20 @@ class StoriesController < ApplicationController
       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
diff --git a/app/helpers/comic_stories_helper.rb b/app/helpers/comic_stories_helper.rb
new file mode 100644 (file)
index 0000000..93633f0
--- /dev/null
@@ -0,0 +1,2 @@
+module ComicStoriesHelper
+end
index 5b7f9dc..86c28e5 100644 (file)
@@ -1,7 +1,7 @@
 #コミック
 class Comic < Peta::Content
   load_manifest
-  has_many :stories, :order => 't'
+  has_many :comic_stories
   belongs_to :author
   
   validates :title, :presence => true, :length => {:maximum => 100}
@@ -32,10 +32,6 @@ class Comic < Peta::Content
     end
   end
   
-  def comic_stories_count
-    Story.where(['stories.comic_id = ?', self.id]).count
-  end
-  
   def symbol_filename
   end
   
@@ -48,19 +44,19 @@ class Comic < Peta::Content
   end
   
   def self.list_opt
-    {:stories => {}, :author => {} }
+    {:comic_stories => {:story => {}}, :author => {} }
   end
   
   def self.list_json_opt
-    {:include => {:stories => {}, :author => {}} }
+    {:include => {:comic_stories => {:include => {:story => {}}}, :author => {}}}
   end
   
   def self.show_opt
-    {:include => {:stories => {}, :author => {}} }
+    {:include => {:comic_stories => {:story => {}}, :author => {}}}
   end
   
   def self.show_json_opt
-    {:include => {:stories => {}, :author => {}} }
+    {:include => {:comic_stories => {:include => {:story => {}}}, :author => {}}}
   end
   
   def tag_attributes column = nil, opt = {}
diff --git a/app/models/comic_story.rb b/app/models/comic_story.rb
new file mode 100644 (file)
index 0000000..9e2fd28
--- /dev/null
@@ -0,0 +1,108 @@
+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
+  
+  def allow? operators
+    return nil if self.story_id == nil or self.comic_id == nil
+    self.comic.own?(operators) and self.story.own?(operators)
+  end
+  
+  def store operators, old_t = nil
+    res = false
+    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
index b6546da..b90eb91 100644 (file)
@@ -24,9 +24,14 @@ class Folder < Peta::SystemResource
   
   def self.add_local parent, name
     key = parent.name + name + '/'
+    attr = {
+      :name => key, :category_id => 0, :t => 0
+    }
     if i = self.find_by_name(key)
+      i.attributes = attr
+      i.save
     else
-      i = self.create :name => key, :category_id => 0, :t => 0
+      i = self.create attr
     end
     i.move_to_child_of parent
     i
@@ -34,11 +39,16 @@ class Folder < Peta::SystemResource
   
   def self.add_remote parent, name, controller_name = nil, action_name = nil
     key = parent.name + name + '/'
+    attr = {
+      :name => key, :category_id => 10, :t => 0, 
+      :controller_name => (controller_name || name), 
+      :action_name => action_name
+    }
     if i = self.find_by_name(key)
+      i.attributes = attr
+      i.save
     else
-      i = self.create :name => key, :category_id => 10, :t => 0, 
-        :controller_name => (controller_name || name), 
-        :action_name => action_name
+      i = self.create attr
     end
     i.move_to_child_of parent
     i
@@ -87,6 +97,7 @@ class Folder < Peta::SystemResource
     docidx_scroll = self.add_remote docidx, 'scrolls'
     docidx_scroll_panel = self.add_remote docidx, 'scroll_panels'
     docidx_comic = self.add_remote docidx, 'comics'
+    docidx_comic_story = self.add_remote docidx, 'comic_stories'
     docidx_story = self.add_remote docidx, 'stories'
     docidx_story_sheet = self.add_remote docidx, 'story_sheets'
     docidx_sheet = self.add_remote docidx, 'sheets'
@@ -123,6 +134,7 @@ class Folder < Peta::SystemResource
     mydocidx_scroll = self.add_remote mydocidx, 'scrolls'
     mydocidx_scroll_panel = self.add_remote mydocidx, 'scroll_panels'
     mydocidx_comic = self.add_remote mydocidx, 'comics'
+    mydocidx_comic_story = self.add_remote mydocidx, 'comic_stories'
     mydocidx_story = self.add_remote mydocidx, 'stories'
     mydocidx_story_sheet = self.add_remote mydocidx, 'story_sheets'
     mydocidx_sheet = self.add_remote mydocidx, 'sheets'
@@ -140,6 +152,13 @@ class Folder < Peta::SystemResource
     mydocedt_scroll = self.add_remote mydocedt, 'new scroll', 'scrolls', 'new'
     mydocedt_panel = self.add_remote mydocedt, 'new panel', 'panels', 'new'
     mydocedt_original_picture = self.add_remote mydocedt, 'upload picture', 'original_pictures', 'new'
+    # child of /my documents/create/index
+    mydocedtidx = self.add_local mydocedt, 'index'
+    mydocedtidx_scroll = self.add_remote mydocedtidx, 'new scroll', 'scrolls', 'new'
+    mydocedtidx_comic = self.add_remote mydocedtidx, 'new comic', 'comics', 'new'
+    mydocedtidx_story = self.add_remote mydocedtidx, 'new story', 'stories', 'new'
+    mydocedtidx_sheet = self.add_remote mydocedtidx, 'new sheet', 'sheets', 'new'
+    mydocedtidx_panel = self.add_remote mydocedtidx, 'new panel', 'panels', 'new'
     
     # child of /system_resource
     sbt = self.add_remote sr, 'speech_balloon_templates'
index b75b417..daea39d 100644 (file)
@@ -66,7 +66,8 @@ class PanelPicture < Peta::Element
   
   def flip
     res = (self.height > 0 ? '' : 'v') + (self.width > 0 ? '' : 'h')
-    res += '/' unless res.empty?
+    res = res # format of /1.png?subdir=v
+    # res += '/' unless res.empty? # format of /v/1.png
     res
   end
   
index 7207179..3db3965 100644 (file)
@@ -111,76 +111,6 @@ class ScrollPanel < Peta::Leaf
     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)
@@ -188,7 +118,7 @@ class ScrollPanel < Peta::Leaf
   
   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
@@ -198,7 +128,7 @@ class ScrollPanel < Peta::Leaf
       end
       res = self.save
       raise ActiveRecord::Rollback unless res
-      res = ScrollPanel.validate_t(self
+      res = self.class.validate_t(self.scroll_id
       unless res
         self.errors.add :t, 'unserialized'
         raise ActiveRecord::Rollback 
@@ -207,14 +137,4 @@ class ScrollPanel < Peta::Leaf
     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
index f47f192..a4d3fde 100644 (file)
@@ -166,76 +166,6 @@ class SheetPanel < Peta::Element
     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)
@@ -243,7 +173,7 @@ class SheetPanel < Peta::Element
   
   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
@@ -253,7 +183,7 @@ class SheetPanel < Peta::Element
       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 
@@ -262,14 +192,4 @@ class SheetPanel < Peta::Element
     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
index 2d09d53..1410b11 100644 (file)
@@ -1,38 +1,33 @@
 #ストーリー
 class Story < Peta::Binder
   load_manifest
+  has_many :comic_stories
   has_many :story_sheets
-  belongs_to :comic
+  belongs_to :author
   
-  validates :comic_id, :presence => true, :numericality => true, :existence => {:both => false}
   validates :title, :presence => true, :length => {:maximum => 100}
   validates :visible, :presence => true, :numericality => true, :inclusion => {:in => 0..1}
-  validates :t, :presence => true, :numericality => {:greater_than_or_equal_to => 0}
+  validates :author_id, :presence => true, :numericality => true, :existence => {:both => false}
   
   def supply_default
-    self.comic_id = nil
     self.visible = 0 if self.visible.blank?
-    self.t = nil
   end
   
-  def overwrite
+  def overwrite operators
+    return false unless operators.author
+    self.author_id = operators.author.id
+    super()
   end
   
   def visible? operators
-    return false unless super
-    self.visible > 0
-  end
-  
-  def disp_t
-    self.t + 1
-  end
-  
-  def disp_t_by_text
-    I18n.t('stories.show.t', :t => self.disp_t)
-  end
-  
-  def title_with_t
-    self.disp_t_by_text  + ':' + self.title
+    case super
+    when nil # super return
+      return true
+    when false
+      return false
+    else
+      self.visible > 0
+    end
   end
   
   def story_sheets_count
@@ -48,27 +43,19 @@ class Story < Peta::Binder
   end
   
   def self.list_opt
-    {:comic => {:author => {}} }
-  end
-  
-  def self.by_author_list_includes
-    {
-      :comic => {
-        :author => {}
-      }
-    }
+    {:comic_stories => {:comic => {}}, :author => {} }
   end
   
   def self.list_json_opt
-    {:include => {:comic => {:include => {:author => {}}} }}
+    {:include => {:comic_stories => {:include => {:comic => {}}}, :author => {}}}
   end
   
   def self.show_opt
-    {:include => {:comic => {:author => {}} }}
+    {:include => {:comic_stories => {:comic => {}}, :author => {}}}
   end
   
   def self.show_json_opt
-    {:include => {:comic => {:include => {:author => {}}} }}
+    {:include => {:comic_stories => {:include => {:comic => {}}}, :author => {}}}
   end
   
   def self.visible_count
@@ -87,97 +74,84 @@ class Story < Peta::Binder
     res
   end
   
-  def self.new_t comic_id
-    r = Story.max_t(comic_id)
-    r.blank? ? 0 : r.to_i + 1
+  def parts_element
+    self.leafs_items
   end
   
-  def self.max_t comic_id
-    Story.maximum(:t, :conditions => ['comic_id = ?', comic_id])
+  def zorderd_elements
+    res = []
+    self.parts_element.each do |e|
+      res[e.z-1] = e
+    end
+    res
   end
   
-  def self.find_t comic_id, t
-    Story.find(:first, :conditions => ['comic_id = ? and t = ?', comic_id, t])
+  def story_elements
+    res = []
+    self.parts_element.each do |e|
+      res[e.t] = e
+    end
+    res
   end
   
-  def self.collect_t story
-    r = Story.find(:all, :conditions => ['comic_id = ?', story.comic_id], :order => 't')
-    r.map {|s| s.t}
+  def self.collect_element_value elements, name
+    elements.map {|e|
+      if e['_destroy'] or e[:_destroy]
+        nil
+      else
+        e[name]
+      end
+    }
   end
   
-  def self.serial? ary
-    i = 0
-    ary.compact.sort.each do |t|
-      break false unless t == i
+  def self.validate_serial ary, offset = 0
+    i = offset
+    ary.compact.sort.each do |n|
+      break false unless n == i
       i += 1
     end
-    ary.compact.size == i
-  end
-  
-  def self.validate_t story
-    Story.serial?(Story.collect_t(story))
+    ary.compact.size == i - offset
   end
   
-  def insert_shift
-    Story.update_all('t = t + 1', ['comic_id = ? and t >= ?', self.comic_id, self.t])
+  def self.validate_element_serial elements, name, offset = 0
+    self.validate_serial(self.collect_element_value(elements, name), offset)
   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])
+  def self.validate_elements_serial c
+    c.map {|conf|
+      self.validate_element_serial(conf[:elements], conf[:name], conf[:offset]) ? nil : false
+    }.compact.empty?
   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])
+  def validate_serial_list
+    [
+      {:elements => self.leafs_items, :name => :t, :offset => 0}, 
+      {:elements => self.leafs_items, :name => :z, :offset => 1}
+    ]
   end
-  
-  def update_shift old_t
-    if self.t > old_t
-      higher_shift old_t
-    else
-      lesser_shift old_t
-    end
+  def validate_child
+#    r1 = Panel.validate_elements_id validate_id_list
+    self.class.validate_elements_serial validate_serial_list
   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
+  def store attr, operators
+    if attr == false
+      self.errors.add :base, I18n.t('errors.invalid_json')
+      return false
     end
-  end
-  
-  def allow? operators
-    return nil if self.comic_id == nil
-    self.comic.own?(operators)
-  end
-  
-  def store operators, old_t = nil
+    self.attributes = attr
+    self.overwrite operators
     res = false
     Story.transaction do
-      case self.allow? operators
-      when true
-        self.rotate old_t
-      when false
-        raise ActiveRecord::Forbidden
-      else
+      self.story_elements.each do |elm|
+        elm.new_story = self
+        elm.boost operators
       end
       res = self.save
-      raise ActiveRecord::Rollback unless res
-      res = Story.validate_t(self) 
-      unless res
-        self.errors.add :t, 'unserialized'
-        raise ActiveRecord::Rollback 
+      unless validate_child
+        res = false
+        self.errors.add :base, I18n.t('errors.invalid_t')
+        raise ActiveRecord::Rollback
       end
     end
     res
index 6d02cd0..562caba 100644 (file)
@@ -118,80 +118,10 @@ class StorySheet < Peta::Leaf
     '[' + 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)
@@ -199,7 +129,7 @@ class StorySheet < Peta::Leaf
   
   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
@@ -209,7 +139,7 @@ class StorySheet < Peta::Leaf
       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 
@@ -218,14 +148,4 @@ class StorySheet < Peta::Leaf
     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
diff --git a/app/views/comic_stories/_append_comic.html.erb b/app/views/comic_stories/_append_comic.html.erb
new file mode 100644 (file)
index 0000000..13d9af1
--- /dev/null
@@ -0,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>
diff --git a/app/views/comic_stories/_append_story.html.erb b/app/views/comic_stories/_append_story.html.erb
new file mode 100644 (file)
index 0000000..8ce83b7
--- /dev/null
@@ -0,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>
diff --git a/app/views/comic_stories/_form.html.erb b/app/views/comic_stories/_form.html.erb
new file mode 100644 (file)
index 0000000..0cf77a8
--- /dev/null
@@ -0,0 +1,26 @@
+<%= form_for(@scroll_panel) do |f| %>
+  <%= render 'system/error_explanation', :obj => @scroll_panel %>
+
+  <div class="field">
+    <%= f.label :scroll_id %><br />
+    <%= f.number_field :scroll_id %>
+  </div>
+  <div class="row_break">
+  </div>
+  <div class="field">
+    <%= f.label :t %><br />
+    <%= f.number_field :t %>
+  </div>
+  <div class="row_break">
+  </div>
+  <div class="field">
+    <%= f.label :panel_id %><br />
+    <%= f.number_field :panel_id %>
+  </div>
+  <div class="row_break">
+  </div>
+
+  <div class="actions">
+    <%= f.submit %>
+  </div>
+<% end %>
diff --git a/app/views/comic_stories/_order.html.erb b/app/views/comic_stories/_order.html.erb
new file mode 100644 (file)
index 0000000..6d515f8
--- /dev/null
@@ -0,0 +1,15 @@
+<%= form_for(scroll_panel) do |f| %>
+  <table class="no-border">
+    <tr>
+      <td>
+        No.
+        <%= f.number_field :t, :size => 3 %>
+        <%= f.hidden_field :panel_id %>
+        <%= f.hidden_field :scroll_id %>
+      </td>
+      <td>
+        <%= f.submit t 'scroll_panels.move' %>
+      </td>
+    </tr>
+  </table>
+<% end %>
diff --git a/app/views/comic_stories/_summary.html.erb b/app/views/comic_stories/_summary.html.erb
new file mode 100644 (file)
index 0000000..59204fb
--- /dev/null
@@ -0,0 +1,9 @@
+<div>
+  <%= link_to comic_icon(:object => item.comic, :size => 32), comic_path(item.comic) %>
+  <% if item.story %>
+    <%= link_to story_icon(:object => item.story, :size => 32), story_path(item.story) %>
+  <% end %>
+</div>
+<div>
+  <%= link_to h(truncate(item.comic.author.name, :length => 12)), author_path(item.comic.author) %>
+</div>
diff --git a/app/views/comic_stories/edit.html.erb b/app/views/comic_stories/edit.html.erb
new file mode 100644 (file)
index 0000000..1d67f75
--- /dev/null
@@ -0,0 +1,4 @@
+<h1><%= t('.title') %></h1>
+<p id="notice"><%= notice %></p>
+
+<%= render 'form' %>
diff --git a/app/views/comic_stories/new.html.erb b/app/views/comic_stories/new.html.erb
new file mode 100644 (file)
index 0000000..f33a2f8
--- /dev/null
@@ -0,0 +1,3 @@
+<h1><%= t('.title') %></h1>
+
+<%= render 'form' %>
index 4911dee..b851de5 100644 (file)
@@ -1,6 +1,6 @@
 <div>
   <%= t_selected_item('comic_visible_items', item.visible) %>
-  <%= t('comics.comic_stories_count', :c => item.comic_stories_count) %>
+  <%= t('comics.comic_stories_count', :c => item.comic_stories.count) %>
 </div>
 <div>
   <%= link_to h(truncate(item.author.name, :length => 12)), author_path(item.author) %>
index abc0614..e0a0ef3 100644 (file)
@@ -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 %>
index 9d05abc..940683c 100644 (file)
@@ -1,8 +1,6 @@
 <div>
   <%= t_selected_item('story_visible_items', item.visible) %>
-  <%= t('stories.story_sheets_count', :c => item.story_sheets_count) %>
-  <%= link_to h(item.comic.title), comic_path(item.comic) %>
 </div>
 <div>
-  <%= link_to h(truncate(item.comic.author.name, :length => 12)), author_path(item.comic.author) %>
+  <%= link_to h(truncate(item.author.name, :length => 12)), author_path(item.author) %>
 </div>
index bb5198b..2bc0ea8 100644 (file)
@@ -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>
index 6f9cc26..28f5e3a 100644 (file)
@@ -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| %>
index 92befec..b616534 100644 (file)
@@ -22,6 +22,7 @@ ja:
       scroll: スクロール
       scroll_panel: スクコマ
       comic: コミック
+      comic_story: コミスト
       story: ストーリー
       story_sheet: スト紙
       sheet: 用紙
@@ -98,7 +99,6 @@ ja:
       scroll_panel:
         scroll_id: スクロール
         panel_id: コマ
-        author_id: 編集者
         t: No.
         created_at: 作成
         updated_at: 更新
@@ -109,6 +109,12 @@ ja:
         author_id: 作家
         created_at: 更新
         updated_at: 作成
+      comic_story:
+        comic_id: コミック
+        story_id: ストーリー
+        t: No.
+        created_at: 作成
+        updated_at: 更新
       story:
         comic_id: コミック
         title: タイトル
@@ -121,7 +127,6 @@ ja:
       story_sheet:
         story_id: ストーリー
         sheet_id: 用紙
-        author_id: 編集者
         t: No.
         created_at: 作成
         updated_at: 更新
@@ -636,6 +641,8 @@ ja:
       title: 最近更新したスクコマ
     comics:
       title: 最近更新したコミック
+    comic_stories:
+      title: 最近更新したコミスト
     stories:
       title: 最近更新したストーリー
     story_sheets:
@@ -787,6 +794,38 @@ ja:
     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:
@@ -794,7 +833,6 @@ ja:
       new: 新ストーリー
     show:
       title: ストーリー詳細
-      t: 第%{t}話
     play:
       title: ストーリーを読む
       empty: 用紙はありません
@@ -1236,6 +1274,7 @@ ja:
       to_scrolls: 最近更新したスクロール
       to_scroll_panels: 最近更新したスクコマ
       to_comics: 最近更新したコミック
+      to_comic_stories: 最近更新したコミスト
       to_stories: 最近更新したストーリー
       to_story_sheets: 最近更新したスト紙
       to_sheets: 最近更新した用紙
index e108312..7dcb951 100644 (file)
@@ -40,12 +40,8 @@ Pettanr::Application.routes.draw do
       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
@@ -62,6 +58,7 @@ Pettanr::Application.routes.draw do
     collection do
       get :index
       get :show
+      get :count
       post :create
     end
     member do
@@ -87,18 +84,38 @@ Pettanr::Application.routes.draw 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
@@ -106,16 +123,13 @@ Pettanr::Application.routes.draw do
     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
@@ -132,6 +146,7 @@ Pettanr::Application.routes.draw do
     collection do
       get :index
       get :show
+      get :count
       post :create
     end
     member do
@@ -184,6 +199,7 @@ Pettanr::Application.routes.draw do
     collection do
       get :index
       get :show
+      get :count
       post :create
     end
     member do
@@ -352,6 +368,7 @@ Pettanr::Application.routes.draw do
     collection do
       get :index
       get :show
+      get :count
       post :create
     end
     member do
@@ -365,6 +382,7 @@ Pettanr::Application.routes.draw do
     collection do
       get :index
       get :show
+      get :count
       get :credit
       get :search
       get :list
@@ -378,6 +396,7 @@ Pettanr::Application.routes.draw do
     collection do
       get :index
       get :show
+      get :count
       get :new
       post :create
       get :count
@@ -397,6 +416,7 @@ Pettanr::Application.routes.draw do
     collection do
       get :index
       get :show
+      get :count
     end
     member do
       get :speech_balloons
@@ -412,6 +432,7 @@ Pettanr::Application.routes.draw do
     collection do
       get :index
       get :show
+      get :count
     end
     member do
       get :speeches
@@ -424,6 +445,7 @@ Pettanr::Application.routes.draw do
     collection do
       get :index
       get :show
+      get :count
     end
     member do
       get :licenses
@@ -483,6 +505,7 @@ Pettanr::Application.routes.draw do
     collection do
       get :index
       get :show
+      get :count
     end
     member do
       #get :balloons
diff --git a/db/migrate/20140519235843_create_comic_stories.rb b/db/migrate/20140519235843_create_comic_stories.rb
new file mode 100644 (file)
index 0000000..0e47deb
--- /dev/null
@@ -0,0 +1,12 @@
+class CreateComicStories < ActiveRecord::Migration
+  def change
+    create_table :comic_stories do |t|
+      t.integer :comic_id, :null => false, :default => 0
+      t.integer :story_id, :null => false, :default => 0
+      t.integer :author_id, :null => false, :default => 0
+      t.integer :t, :null => false, :default => 0
+
+      t.timestamps
+    end
+  end
+end
diff --git a/db/migrate/20140520102407_rm_comic_id_on_story.rb b/db/migrate/20140520102407_rm_comic_id_on_story.rb
new file mode 100644 (file)
index 0000000..fc52a7b
--- /dev/null
@@ -0,0 +1,17 @@
+class RmComicIdOnStory < ActiveRecord::Migration
+  def up
+    add_column :stories, :author_id, :integer, :null => false, :default => 0
+    Story.all.each do |s|
+      c = Comic.find(s.comic_id)
+      ComicStory.create! :comic_id => s.comic_id, :story_id => s.id,
+        :author_id => c.author_id, :t => s.t
+      s.author_id = c.author_id
+      s.save!
+    end
+    remove_column :stories, :comic_id
+    remove_column :stories, :t
+  end
+
+  def down
+  end
+end
index 7f4a5b3..16afd72 100644 (file)
@@ -12,6 +12,10 @@ module Peta
       define_singleton_method("parent_model") do 
         pm
       end
+      pfk = self.my_peta.parent_model_name + '_id'
+      define_singleton_method("binder_key") do 
+        pfk
+      end
       # Instance Methods
     end
     
@@ -67,20 +71,20 @@ module Peta
     end
     
     def self.new_t binder_id
-      r = ScrollPanel.max_t(binder_id)
+      r = self.max_t(binder_id)
       r.blank? ? 0 : r.to_i + 1
     end
     
     def self.max_t binder_id
-      self.class..maximum(:t, :conditions => ['scroll_id = ?', binder_id])
+      self.maximum(:t, :conditions => [self.binder_key + ' = ?', binder_id])
     end
     
     def self.find_t binder_id, t
-      self.class.find(:first, :conditions => ['scroll_id = ? and t = ?', binder_id, t])
+      self.find(:first, :conditions => [self.binder_key + ' = ? and t = ?', binder_id, t])
     end
     
-    def self.collect_t scroll_panel
-      r = self.class.find(:all, :conditions => ['scroll_id = ?', scroll_panel.scroll_id], :order => 't')
+    def self.collect_t binder_id
+      r = self.find(:all, :conditions => [self.binder_key + ' = ?', binder_id], :order => 't')
       r.map {|sp| sp.t}
     end
     
@@ -88,11 +92,6 @@ module Peta
       StorySheet.play_list(story, author).first
     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|
@@ -102,24 +101,38 @@ module Peta
       ary.compact.size == i
     end
     
-    def self.validate_t scroll_panel
-      ScrollPanel.serial?(ScrollPanel.collect_t(scroll_panel))
+    def self.validate_t binder_id
+      self.serial?(self.collect_t(binder_id))
+    end
+    
+    def binder_key
+      self.class.binder_key
+    end
+    
+    def binder_id
+      self.attributes[self.binder_key]
     end
     
     def insert_shift
-      ScrollPanel.update_all('t = t + 1', ['scroll_id = ? and t >= ?', self.scroll_id, self.t])
+      self.class.update_all('t = t + 1', 
+        [self.binder_key + ' = ? and t >= ?', self.binder_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])
+      self.class.update_all('t = t + 1', 
+        [self.binder_key + ' = ? and (t >= ? and t < ?)', self.binder_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
+      nf = self.class.find_t(self.binder_id, self.t)
+      max_t = self.class.max_t(self.binder_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])
+      self.class.update_all('t = t - 1', 
+        [self.binder_key + ' = ? and (t > ? and t <= ?)', self.binder_id, old_t, self.t]
+      )
     end
     
     def update_shift old_t
@@ -133,7 +146,7 @@ module Peta
     def rotate old_t = nil
       if self.new_record?
         if self.t.blank?
-          self.t = ScrollPanel.new_t self.scroll_id
+          self.t = self.class.new_t self.binder_id
         else
           self.insert_shift
         end
@@ -145,15 +158,12 @@ module Peta
       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)
-    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])
+      self.class.transaction do
+        self.class.update_all('t = t - 1', 
+          [self.binder_key + ' = ? and (t > ?)', self.binder_id, self.t]
+        )
         raise ActiveRecord::Rollback unless self.destroy
         res = true
       end
diff --git a/public/images/comic_story.gif b/public/images/comic_story.gif
new file mode 100644 (file)
index 0000000..0707502
Binary files /dev/null and b/public/images/comic_story.gif differ
index aac9867..daf04e7 100644 (file)
         },\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
index 2d94439..0f3a5ab 100644 (file)
       "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
diff --git a/spec/controllers/comic_stories_controller_spec.rb b/spec/controllers/comic_stories_controller_spec.rb
new file mode 100644 (file)
index 0000000..9d81946
--- /dev/null
@@ -0,0 +1,5 @@
+require 'spec_helper'
+
+describe ComicStoriesController do
+
+end
diff --git a/spec/helpers/comic_stories_helper_spec.rb b/spec/helpers/comic_stories_helper_spec.rb
new file mode 100644 (file)
index 0000000..06dbc6c
--- /dev/null
@@ -0,0 +1,15 @@
+require 'spec_helper'
+
+# Specs in this file have access to a helper object that includes
+# the ComicStoriesHelper. For example:
+#
+# describe ComicStoriesHelper do
+#   describe "string concat" do
+#     it "concats two strings with spaces" do
+#       helper.concat_strings("this","that").should == "this that"
+#     end
+#   end
+# end
+describe ComicStoriesHelper do
+  pending "add some examples to (or delete) #{__FILE__}"
+end
diff --git a/spec/models/comic_story_spec.rb b/spec/models/comic_story_spec.rb
new file mode 100644 (file)
index 0000000..9ec5a24
--- /dev/null
@@ -0,0 +1,5 @@
+require 'spec_helper'
+
+describe ComicStory do
+  pending "add some examples to (or delete) #{__FILE__}"
+end