Last active
August 29, 2015 14:15
-
-
Save parrot-studio/b937179bff3d61f69df5 to your computer and use it in GitHub Desktop.
react.jsをお試し中
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
searchArcanas = (query, path, component, callback) -> | |
component.setState(showError: false) | |
$("#loading-modal").modal('show') | |
query ?= {} | |
query.ver = $("#data-ver").val() | |
url = $("#app-path").val() + path | |
callbacks = | |
done: (as) -> | |
callback(as, component) | |
$("#loading-modal").modal('hide') | |
fail: -> | |
$("#loading-modal").modal('hide') | |
component.setState(showError: true) | |
switch path | |
when 'ptm' | |
Searcher.searchMembers(query, url, callbacks) | |
when 'codes' | |
Searcher.searchCodes(query, url, callbacks) | |
else | |
Searcher.search(query, url, callbacks) | |
Row = ReactBootstrap.Row | |
Col = ReactBootstrap.Col | |
Well = ReactBootstrap.Well | |
Alert = ReactBootstrap.Alert | |
Button = ReactBootstrap.Button | |
Badge = ReactBootstrap.Badge | |
Glyphicon = ReactBootstrap.Glyphicon | |
Label = ReactBootstrap.Label | |
HeaderArea = React.createClass | |
render: -> | |
`<div className="header"> | |
<h1> | |
Get our light! | |
<span className="hidden-sm hidden-md hidden-lg"><br /></span> | |
<small className="text-muted lead">チェンクロ パーティーシミュレーター</small> | |
</h1> | |
</div>` | |
ErrorArea = React.createClass | |
render: -> | |
return null unless @props.show | |
url = location.href | |
`<Row> | |
<Col xs={12} md={12} sm={12}> | |
<Alert bsStyle="danger"> | |
<p> | |
<strong>データの取得に失敗しました。</strong> | |
<a href={url} className="alert-link">リロードする</a>か、もう一度検索してください。 | |
</p> | |
</Alert> | |
</Col> | |
</Row>` | |
ArcanaSkill = React.createClass | |
renderEffect: (ef, i) -> | |
sd = "" | |
sd += "=> " if i > 0 | |
sd += Skill.typeNameFor(ef.category) | |
sd += " - " | |
sd += Skill.subnameFor(ef.category, ef.subcategory) | |
if Skill.subeffectForEffect(ef).length > 0 | |
se = [] | |
for e in Skill.subeffectForEffect(ef) | |
se.push Skill.effectNameFor(ef.category, e) | |
sd += " ( + #{se.join(' / ')} )" | |
`<li key={i}>{sd}</li>` | |
render: -> | |
sk = @props.skill | |
return `<span>(不明)</span>` unless sk | |
efs = [] | |
for ef, i in sk.effects | |
efs.push @renderEffect(ef, i) | |
`<div> | |
{sk.name} ({sk.cost})<br /> | |
<ul className='small list-unstyled ability-detail'> | |
{efs} | |
</ul> | |
</div>` | |
ArcanaAbility = React.createClass | |
render: -> | |
ab = @props.ability | |
return `<span>なし</span>` unless ab | |
efs = [] | |
for e, i in ab.effects | |
efs.push `<li key={i}>{Ability.conditionNameFor(e.conditionType)} - {Ability.effectNameFor(e.effectType)}</li>` | |
`<div> | |
{ab.name} | |
<ul className='small list-unstyled ability-detail'> | |
{efs} | |
</ul> | |
</div>` | |
ArcanaDetail = React.createClass | |
render: -> | |
a = @props.arcana | |
return null unless a | |
cl = "#{a.jobClass} arcana" | |
`<div className={cl}> | |
<ArcanaHeader arcana={a} /> | |
<div className='arcana-view-body'> | |
<h4 className='arcana-name'> | |
<span className='text-muted'>{a.title}</span> | |
<strong>{a.name}</strong> | |
</h4> | |
<Row> | |
<div className='col-xs-12 hidden-sm hidden-md hidden-lg'> | |
<p className='pull-right'> | |
<input type='checkbox' className='fav' data-job-code={a.jobCode} /> | |
</p> | |
</div> | |
<Col xs={12} sm={4} md={4}> | |
<dl className='small arcana-view-detail'> | |
<dt>職業</dt> | |
<dd>{a.jobDetail}</dd> | |
<dt>ATK / HP</dt> | |
<dd>{a.maxAtk} / {a.maxHp}<br />( {a.limitAtk} / {a.limitHp} )</dd> | |
<dt>武器タイプ</dt> | |
<dd>{a.weaponName}</dd> | |
<dt>所属</dt> | |
<dd>{Arcana.unionNameFor(a.union)}</dd> | |
<dt>声優</dt> | |
<dd>{a.voiceActor}</dd> | |
<dt>イラストレーター</dt> | |
<dd>{a.illustrator}</dd> | |
<dt>入手先</dt> | |
<dd>{Arcana.sourceCategoryNameFor(a.sourceCategory)} - {Arcana.sourceNameFor(a.sourceCategory, a.source)}</dd> | |
</dl> | |
</Col> | |
<Col xs={12} sm={8} md={8}> | |
<dl className='small arcana-view-detail'> | |
<dt>スキル</dt> | |
<dd><ArcanaSkill skill={a.skill} /></dd> | |
<dt>アビリティ1</dt> | |
<dd><ArcanaAbility ability={a.firstAbility} /></dd> | |
<dt>アビリティ2</dt> | |
<dd><ArcanaAbility ability={a.secondAbility} /></dd> | |
<dt>絆アビリティ</dt> | |
<dd><ArcanaAbility ability={a.chainAbility} /></dd> | |
</dl> | |
</Col> | |
<Col xs={12} sm={12} md={12}> | |
<p className='pull-left'> | |
<Button>Wikiで確認</Button> | |
</p> | |
<p className='pull-right hidden-xs'> | |
<input type='checkbox' className='fav' data-job-code={a.jobCode} /> | |
</p> | |
</Col> | |
</Row> | |
</div> | |
</div>` | |
MemberArcanaHeader = React.createClass | |
render: -> | |
m = @props.member | |
return null unless m | |
a = m.arcana | |
return null unless a | |
cl = "arcana-title small #{a.jobClass}-title" | |
cost = a.cost | |
cost += " + #{m.chainArcana.chainCost}" if m.chainArcana | |
`<div className={cl}> | |
{a.jobNameShort} : {a.rarityStars} <Badge className='pull-right'>{cost}</Badge> | |
</div>` | |
ArcanaHeader = React.createClass | |
render: -> | |
a = @props.arcana | |
return null unless a | |
cl = "arcana-title small #{a.jobClass}-title" | |
cost = "#{a.cost} ( #{a.chainCost} )" | |
`<div className={cl}> | |
{a.jobNameShort} : {a.rarityStars} <Badge className='pull-right'>{cost}</Badge> | |
</div>` | |
ArcanaInfoButton = React.createClass | |
viewModalShow: -> | |
a = @props.arcana | |
React.render `<ArcanaDetail arcana={a} />`, document.getElementById('view-detail') | |
# TODO 管理の方法を検討 | |
$(".fav").bootstrapSwitch({ | |
state: false # TODO | |
size: 'mini' | |
onColor: 'success' | |
labelText: 'お気に入り' | |
onSwitchChange: (e, state) -> | |
target = $(e.target) | |
# TODO 実装 | |
#toggleFavoriteArcana(target.data('jobCode'), state) | |
}) | |
render: -> | |
_show = @viewModalShow | |
`<Button bsSize="xsmall" | |
className="pull-right" | |
data-toggle='modal' | |
data-target='#view-modal' | |
onClick={_show}>Info</Button>` | |
ChainedArcana = React.createClass | |
renderWithLink: -> | |
m = @props.member | |
return null unless m | |
c = m.chainArcana | |
return null unless c | |
abn = if m.canUseChainAbility() | |
`<span className='chained-ability'>{c.chainAbility.name}</span>` | |
else | |
`<s>{c.chainAbility.name}</s>` | |
_ubc = m.unbindChain | |
`<span> | |
<button className='close' onClick={_ubc}>×</button> | |
<a>{c.name}</a> | |
<span> / </span> | |
{abn} | |
</span>` | |
renderNoLink: -> | |
m = @props.member | |
return null unless m | |
c = m.chainArcana | |
return null unless c | |
abn = if m.canUseChainAbility() | |
`<span>{c.chainAbility.name}</span>` | |
else | |
`<s>{c.chainAbility.name}</s>` | |
`<span>{c.name} / {abn}</span>` | |
render: -> | |
if @props.noLink | |
@renderNoLink() | |
else | |
@renderWithLink() | |
ChainedArcanaForSelect = React.createClass | |
render: -> | |
a = @props.arcana | |
c = @props.chain | |
return null unless (a && c) | |
return `<span>({a.chainAbility.name})</span>` if a.jobCode is c.jobCode | |
abn = if Arcana.canUseChainAbility(a, c) | |
`<span className='chained-ability'>{c.chainAbility.name}</span>` | |
else | |
`<s>{c.chainAbility.name}</s>` | |
`<span> | |
<span className='chained-ability'>{c.name}</span> | |
<span> / </span> | |
{abn} | |
</span>` | |
ArcanaName = React.createClass | |
render: -> | |
a = @props.arcana | |
return null unless a | |
button = (if @props.noInfo then null else `<ArcanaInfoButton arcana={a} />`) | |
`<p> | |
<small> | |
{button} | |
<span className='text-muted small'>{a.title}</span><br /> | |
<strong>{a.name}</strong> | |
</small> | |
</p>` | |
ArcanaSummaryData = React.createClass | |
render: -> | |
a = @props.arcana | |
m = @props.member | |
a = m?.arcana unless a | |
return null unless a | |
ca = @props.chain | |
abs1 = (if a.firstAbility.name != '' then a.firstAbility.name else 'なし') | |
abs2 = (if a.secondAbility.name != '' then a.secondAbility.name else 'なし') | |
chain = if m | |
if m.chainArcana | |
nl = @props.noLink | |
`<ChainedArcana member={m} noLink={nl} />` | |
else | |
`<span>({a.chainAbility.name})</span>` | |
else if ca | |
`<ChainedArcanaForSelect arcana={a} chain={ca} />` | |
else | |
`<span>{a.chainAbility.name}</span>` | |
`<div> | |
<small> | |
<ul className='small text-muted list-unstyled summary-detail'> | |
<li>{a.maxAtk} / {a.maxHp}</li> | |
<li>{a.skill.name} ({a.skill.cost})</li> | |
<li>{abs1}<br />{abs2}</li> | |
<li className='chain-ability-name'>{chain}</li> | |
</ul> | |
</small> | |
</div>` | |
MemberArcanaSummaryBody = React.createClass | |
render: -> | |
m = @props.member | |
return null unless (m && m.arcana) | |
`<div className='arcana-summary'> | |
<ArcanaName arcana={m.arcana} /> | |
<ArcanaSummaryData member={m} /> | |
</div>` | |
MemberArcanaSummary = React.createClass | |
componentDidMount: -> | |
d = $(@getDOMNode()) | |
d.draggable( | |
connectToSortable: false | |
containment: false | |
helper: 'clone' | |
opacity: 0.7 | |
zIndex: 10000 | |
start: -> | |
document.getElementById('search-area').className = 'hide' | |
React.render `<HelpArea />`, document.getElementById('help-area') | |
stop: -> | |
document.getElementById('search-area').className = '' | |
React.render `<div />`, document.getElementById('help-area') | |
) | |
render: -> | |
m = @props.member | |
a = m?.arcana | |
cl = "summary-size arcana " | |
cl += (if a then a.jobClass else "none") | |
`<div className="member-character" data-area-id={m.areaId}> | |
<div className={cl}> | |
<MemberArcanaHeader member={m} /> | |
<MemberArcanaSummaryBody member={m} /> | |
</div> | |
</div>` | |
ChainSelectModal = React.createClass | |
setChainArcana: -> | |
m = @props.member | |
rm = @props.replaceMember | |
ca = (if rm then rm.arcana else @props.replaceArcana) | |
m.setArcana(m.arcana, ca) | |
$('#select-modal').modal('hide') | |
replaceMember: -> | |
m = @props.member | |
rm = @props.replaceMember | |
a = (if rm then rm.arcana else @props.replaceArcana) | |
c = (if rm then rm.chainArcana else null) | |
m.setArcana(a, c) | |
$('#select-modal').modal('hide') | |
renderChainedArcana: -> | |
a = @props.member.arcana | |
rm = @props.replaceMember | |
ca = (if rm then rm.arcana else @props.replaceArcana) | |
cl = "summary-size arcana #{a.jobClass}" | |
mcl = "arcana-title small #{a.jobClass}-title" | |
cost = "#{a.cost} + #{ca.chainCost}" | |
`<div className={cl}> | |
<div className={mcl}> | |
{a.jobNameShort} : {a.rarityStars} <Badge className='pull-right'>{cost}</Badge> | |
</div> | |
<div className='arcana-summary'> | |
<ArcanaName arcana={a} noInfo={true} /> | |
<ArcanaSummaryData arcana={a} chain={ca} /> | |
</div> | |
</div>` | |
renderChainState: -> | |
a = @props.member.arcana | |
rm = @props.replaceMember | |
ca = (if rm then rm.arcana else @props.replaceArcana) | |
ab = if Arcana.canUseChainAbility(a, ca) | |
`<Label bsStyle="success">絆アビリティ使用可能</Label>` | |
else | |
`<Label bsStyle="danger">絆アビリティ使用不可</Label>` | |
union = if a.union == ca.union | |
`<Label bsStyle="success">所属ボーナスあり</Label>` | |
else | |
`<Label bsStyle="warning">所属ボーナスなし</Label>` | |
`<div>{ab} {union}</div>` | |
renderReplaced: -> | |
rm = @props.replaceMember | |
ra = @props.replaceArcana | |
if rm | |
@renderReplacedWithMember(rm) | |
else | |
@renderReplacedWithArcana(ra) | |
renderReplacedWithMember: (m) -> | |
return null unless m | |
a = m.arcana | |
return null unless a | |
cl = "summary-size arcana #{a.jobClass}" | |
mcl = "arcana-title small #{a.jobClass}-title" | |
`<div className={cl}> | |
<MemberArcanaHeader member={m} /> | |
<div className='arcana-summary'> | |
<ArcanaName arcana={a} noInfo={true} /> | |
<ArcanaSummaryData member={m} noLink={true} /> | |
</div> | |
</div>` | |
renderReplacedWithArcana: (a) -> | |
return null unless a | |
cl = "summary-size arcana #{a.jobClass}" | |
mcl = "arcana-title small #{a.jobClass}-title" | |
`<div className={cl}> | |
<div className={mcl}> | |
{a.jobNameShort} : {a.rarityStars} <Badge className='pull-right'>{a.cost}</Badge> | |
</div> | |
<div className='arcana-summary'> | |
<ArcanaName arcana={a} noInfo={true} /> | |
<ArcanaSummaryData arcana={a} chain={a} /> | |
</div> | |
</div>` | |
render: -> | |
renderChained = @renderChainedArcana() | |
renderReplaced = @renderReplaced() | |
renderChainState = @renderChainState() | |
_sc = @setChainArcana | |
_rm = @replaceMember | |
`<div className="modal-dialog"> | |
<div className="modal-content"> | |
<div className="modal-header"> | |
<button className="close" data-dismiss="modal"><span aria-hidden="true">× Close</span></button> | |
<h2 className="modal-title">セット先選択</h2> | |
</div> | |
<div className="modal-body"> | |
<Row> | |
<Col sm={6} md={6}> | |
<Button bsStyle="primary" onClick={_sc}> | |
<Glyphicon glyph="link" /> 絆として追加する | |
</Button> | |
<p className="clearfix"></p> | |
<label>絆設定後</label> | |
<Col sm={10} md={10}> | |
{renderChained} | |
</Col> | |
{renderChainState} | |
</Col> | |
<Col sm={6} md={6}> | |
<Button bsStyle="info" onClick={_rm}> | |
<Glyphicon glyph="user" /> メンバーとして置き換える | |
</Button> | |
<p className="clearfix"></p> | |
<label>置き換え後</label> | |
<Col sm={10} md={10}> | |
{renderReplaced} | |
</Col> | |
</Col> | |
</Row> | |
</div> | |
<div className="modal-footer"> | |
<Button data-dismiss="modal"> | |
<Glyphicon glyph="remove" /> セットしないで閉じる | |
</Button> | |
</div> | |
</div> | |
</div>` | |
MemberArcana = React.createClass | |
replaceMemberFromMember: (omem, rmem) -> | |
return if omem.areaId is rmem.areaId | |
unless omem.arcana | |
omem.setArcana(rmem.arcana, rmem.chainArcana) | |
rmem.deleteMember() unless omem.areaId is 'friend' | |
else | |
React.render `<ChainSelectModal member={omem} replaceMember={rmem} />`, document.getElementById('select-modal') | |
$("#select-modal").modal("show") | |
replaceMemberFromTarget: (omem, ta) -> | |
unless omem.arcana | |
omem.setArcana(ta) | |
return | |
React.render `<ChainSelectModal member={omem} replaceArcana={ta} />`, document.getElementById('select-modal') | |
$("#select-modal").modal("show") | |
handleDropedArcana: (mem, drag) -> | |
areaId = drag.data("areaId") # from member | |
code = drag.data("jobCode") # from target | |
if areaId | |
dmem = mem.members.memberForId(areaId) | |
@replaceMemberFromMember(mem, dmem) | |
else if code | |
a = Searcher.forCode(code) | |
@replaceMemberFromTarget(mem, a) | |
componentDidMount: -> | |
d = $(@getDOMNode()) | |
d.droppable( | |
drop: (e, ui) => | |
e.preventDefault() | |
@handleDropedArcana(@props.member, ui.draggable) | |
) | |
render: -> | |
headers = | |
mem1: "Leader" | |
mem2: "2nd" | |
mem3: "3rd" | |
mem4: "4th" | |
sub1: "Sub1" | |
sub2: "Sub2" | |
friend: "Friend" | |
m = @props.member | |
h = headers[m.areaId] | |
_dm = m.deleteMember | |
delbtn = if m.arcana | |
`<button className="close" aria-hidden="true" onClick={_dm}>×</button>` | |
else | |
null | |
`<li className="col-xs-6 col-sm-3 col-md-3"> | |
{delbtn} | |
<label className="member-label">{h}</label> | |
<MemberArcanaSummary member={m} /> | |
</li>` | |
TotalCost = React.createClass | |
render: -> | |
cost = (@props.cost || 0) | |
`<li className="col-xs-6 col-sm-3 col-md-3"> | |
<p className="text-center"> | |
<label>Total Cost</label><br /> | |
<span className="cost">{cost}</span> | |
</p> | |
</li>` | |
MemberAreaHeader = React.createClass | |
render: -> | |
`<Row> | |
<Col md={12} sm={12} className="hidden-xs"> | |
<h2>パーティー編集</h2> | |
</Col> | |
</Row>` | |
MemberArea = React.createClass | |
render: -> | |
members = @props.members | |
return null unless members | |
mems = [] | |
members.eachMembers (k, m) => | |
mems.push `<MemberArcana key={k} member={m} />` | |
`<Well bsSize="small"> | |
<MemberAreaHeader /> | |
<Row> | |
<Col xs={12} sm={12} md={12} className="member-list"> | |
<ul className="list-inline"> | |
{mems} | |
<TotalCost cost={members.cost} /> | |
</ul> | |
</Col> | |
</Row> | |
</Well>` | |
EditButton = React.createClass | |
viewShareModal: -> | |
mems = @props.members | |
return null unless mems | |
console.log document.getElementById('app-path') | |
appUrl = document.getElementById('app-path').value | |
url = appUrl + mems.createCode() | |
document.getElementById('ptm-code').value = url | |
twitterUrl = "https://twitter.com/intent/tweet" | |
twitterUrl += "?text=#{encodeURIComponent('チェンクロ パーティーシミュレーター ' + url)}" | |
twitterUrl += "&hashtags=ccpts" | |
document.getElementById('twitter-share').href = twitterUrl | |
render: -> | |
mems = @props.members | |
return null unless mems | |
edit = if mems.editMode | |
`<Button bsStyle="primary" className="act-btn"> | |
<Glyphicon glyph="check" /> 編集終了 | |
</Button>` | |
else | |
`<Button bsStyle="primary" className="act-btn"> | |
<Glyphicon glyph="edit" /> 編集する | |
</Button>` | |
_vsm = @viewShareModal | |
`<Row> | |
<Col sm={12} md={12}> | |
{edit} | |
<Button | |
bsStyle="info" | |
className="act-btn" | |
data-toggle="modal" | |
data-target="#share-ptm-modal" | |
onClick={_vsm}> | |
<Glyphicon glyph="cloud" /> 共有 | |
</Button> | |
<Button bsStyle="link" className="act-btn" data-toggle="modal" data-target="#help-modal"> | |
使い方 | |
</Button> | |
</Col> | |
</Row>` | |
EditArea = React.createClass | |
render: -> | |
mems = @props.members | |
`<div> | |
<EditButton members={mems} /> | |
<MemberArea members={mems} /> | |
</div>` | |
TargetArcanaBody = React.createClass | |
render: -> | |
a = @props.arcana | |
return null unless a | |
`<div className='arcana-summary'> | |
<ArcanaName arcana={a} /> | |
<ArcanaSummaryData arcana={a} /> | |
</div>` | |
TargetArcana = React.createClass | |
componentDidMount: -> | |
return unless @props.arcana | |
d = $(@getDOMNode()) | |
d.draggable( | |
connectToSortable: false | |
containment: false | |
helper: 'clone' | |
opacity: 0.7 | |
zIndex: 10000 | |
start: -> | |
document.getElementById('search-area').className = 'hide' | |
React.render `<HelpArea />`, document.getElementById('help-area') | |
stop: -> | |
document.getElementById('search-area').className = '' | |
React.render `<div />`, document.getElementById('help-area') | |
) | |
render: -> | |
a = @props.arcana | |
cl = "summary-size arcana " | |
cl += (if a then a.jobClass else "none") | |
code = (if a then a.jobCode else null) | |
`<div className={cl} data-job-code={code}> | |
<ArcanaHeader arcana={a} /> | |
<TargetArcanaBody arcana={a} /> | |
</div>` | |
TargetArcanas = React.createClass | |
render: -> | |
results = @props.results | |
return null unless results | |
ts = [] | |
for a, i in results.targets() | |
ts.push `<li className='listed-character col-sm-3 col-md-3 col-xs-6' key={a.jobCode}> | |
<TargetArcana arcana={a} /> | |
</li>` | |
`<div> | |
<ul className="list-inline"> | |
{ts} | |
</ul> | |
</div>` | |
PageLink = React.createClass | |
jumpPage: (e)-> | |
results = @props.results | |
return null unless results | |
page = e.target.dataset.page | |
results.jumpPage(page) | |
renderPage: (p, i) -> | |
return null unless p | |
results = @props.results | |
return null unless results | |
page = results.page() | |
_jp = @jumpPage | |
if p is page | |
`<li key={i} className="active"><span>{p}</span></li>` | |
else if p is '..' | |
`<li key={i} className="disable"><span>{p}</span></li>` | |
else | |
`<li key={i}><span onClick={_jp} data-page={p}>{p}</span></li>` | |
renderPrevPage: -> | |
results = @props.results | |
return null unless results | |
if results.hasPrevPage() | |
_pp = results.prevPage | |
`<li><span onClick={_pp}>←</span></li>` | |
else | |
`<li className="disabled"><span>←</span></li>` | |
renderNextPage: -> | |
results = @props.results | |
return null unless results | |
if results.hasNextPage() | |
_np = results.nextPage | |
`<li><span onClick={_np}>→</span></li>` | |
else | |
`<li className="disabled"><span>→</span></li>` | |
render: -> | |
results = @props.results | |
return null unless results | |
pager = results.pager | |
return null unless pager | |
isPhone = @props.isPhone | |
pcl = "pagination" | |
pcl += " pagination-sm" if isPhone | |
prev = @renderPrevPage() | |
next = @renderNextPage() | |
plist = if isPhone | |
results.paginationList(3, 1) | |
else | |
results.paginationList(5, 2) | |
pl = [] | |
for p, i in plist | |
pl.push @renderPage(p, i) | |
`<nav className="text-center"> | |
<ul className={pcl}> | |
{prev} | |
{pl} | |
{next} | |
</ul> | |
</nav>` | |
HelpArea = React.createClass | |
render: -> | |
`<Row> | |
<Col sm={12} md={12}> | |
<Alert bsStyle="warning" className="small"> | |
<ul className="list-unstyled"> | |
<li>空いたところにドロップ -> パーティーメンバーとしてセット</li> | |
<li>すでに登録されたところにドロップ -> 「置き換え」か「絆」か選択</li> | |
</ul> | |
</Alert> | |
</Col> | |
</Row>` | |
SearchArea = React.createClass | |
render: -> | |
results = @props.results | |
return null unless results | |
pager = results.pager | |
count = if pager.size > 0 | |
"(#{pager.head() + 1} - #{pager.tail() + 1} / #{pager.size}件)" | |
else | |
"(0件)" | |
# TODO 検索にあった文字列 | |
str = "最新" | |
`<Row> | |
<Col sm={12} md={12}> | |
<div className="bg-info small text-muted"> | |
<div className="btn-group pull-right"> | |
<Button className="dropdown-toggle" data-toggle="dropdown"> | |
<Glyphicon glyph="menu-hamburger" /> 履歴 <span className="caret"></span> | |
</Button> | |
<ul className="dropdown-menu" role="menu"> | |
<li><a><Glyphicon glyph="refresh" /> 最新のアルカナ</a></li> | |
<li><a><Glyphicon glyph="star" /> お気に入り</a></li> | |
<li><a><Glyphicon glyph="export" /> 最後に作ったパーティー構成</a></li> | |
<li className="divider"></li> | |
<li role="presentation" className="dropdown-header">検索履歴</li> | |
</ul> | |
</div> | |
<Button bsStyle="primary" data-toggle="modal" data-target="#search-modal"> | |
<Glyphicon glyph="search" /> 検索 | |
</Button> | |
表示中:{str} <span className="pager-count">{count}</span> | |
</div> | |
<div> | |
<span className="help-block small">アルカナをドラッグ -> 上のパーティーエリアでドロップ</span> | |
</div> | |
</Col> | |
</Row>` | |
TargetArea = React.createClass | |
render: -> | |
results = @props.results | |
`<div> | |
<div id="help-area"></div> | |
<div id="search-area"><SearchArea results={results} /></div> | |
<TargetArcanas results={results} /> | |
<PageLink results={results} /> | |
</div>` | |
class SearchResult | |
constructor: (view, rs) -> | |
psize = (view.state.pagerSize || 8) | |
@pager = new Pager(rs, psize) | |
@component = view | |
@search: (query, view) -> | |
unless query | |
result = new SearchResult(view, []) | |
result.updateState() | |
return | |
searchArcanas query, 'arcanas', view, (as, component) -> | |
result = new SearchResult(component, as) | |
result.updateState() | |
updateState: -> | |
@component.setState(results: @) | |
targets: -> | |
@pager.get() || [] | |
page: -> | |
@pager.page | |
hasPrevPage: -> | |
@pager.hasPrevPage() | |
prevPage: => | |
@pager.prevPage() | |
@updateState() | |
hasNextPage: -> | |
@pager.hasNextPage() | |
nextPage: => | |
@pager.nextPage() | |
@updateState() | |
jumpPage: (n) -> | |
@pager.jumpPage(n) | |
@updateState() | |
paginationList: (body, edge) -> | |
return [] unless @pager | |
return [1 .. @pager.maxPage] if (@pager.maxPage <= (body + edge * 2 + 2)) | |
switch | |
when @pager.page <= (edge + (body+1)/2) | |
li = [1 .. (body + edge)] | |
li.push '..' | |
li = li.concat [(@pager.maxPage - edge + 1) .. @pager.maxPage] | |
li | |
when @pager.page >= (@pager.maxPage - (edge + (body+1)/2) + 1) | |
li = [1 .. edge] | |
li.push '..' | |
li = li.concat [(@pager.maxPage-(body + edge)+1) .. @pager.maxPage] | |
li | |
else | |
li = [1 .. edge] | |
li.push '..' | |
li = li.concat [(@pager.page - edge) .. (@pager.page + edge)] | |
li.push '..' | |
li = li.concat [(@pager.maxPage - edge + 1) .. @pager.maxPage] | |
li | |
class Member | |
constructor: (aid, mems, a) -> | |
@areaId = aid | |
@members = mems | |
@arcana = a | |
@chainArcana = null | |
chainedCost: -> | |
return 0 unless @arcana | |
c = @arcana.cost | |
return c unless @chainArcana | |
(c + @chainArcana.chainCost) | |
canUseChainAbility: -> | |
return false unless (@arcana && @chainArcana) | |
return false unless @arcana.jobType == @chainArcana.jobType | |
return false if @arcana.name == @chainArcana.name | |
true | |
deleteMember: => | |
@arcana = null | |
@chainArcana = null | |
@members.updateState() | |
unbindChain: => | |
@chainArcana = null | |
@members.updateState() | |
setArcana: (a, c) -> | |
@arcana = a | |
@chainArcana = c | |
@members.updateState() | |
@members.removeDuplicateMember(@) | |
class Members | |
defaultMemberCode = 'V2F82F85K51NA38NP28NP24NNNNN' | |
memberKeys = ['mem1', 'mem2', 'mem3', 'mem4', 'sub1', 'sub2', 'friend'] | |
ver = document.getElementById('pt-ver').value | |
constructor: (component) -> | |
@ptm = {} | |
@component = component | |
@editMode = true | |
@initMembers: (view, code) -> | |
c = code || defaultMemberCode | |
query = ptm: c | |
searchArcanas query, 'ptm', view, (as, component) -> | |
mems = new Members(component) | |
for k in memberKeys | |
ma = as[k] | |
mc = as[k + 'c'] | |
m = new Member(k, mems, ma) | |
if ma && mc | |
m.chainArcana = mc | |
mems.addMember(m) | |
mems.updateState() | |
memberForId: (aid) -> | |
@ptm[aid] | |
eachMembers: (f) -> | |
for k in memberKeys | |
f(k, @ptm[k]) | |
updateState: -> | |
@cost = calcTotalCost(@ptm) | |
@component.setState(members: @) | |
addMember: (m) -> | |
return unless m | |
@ptm[m.areaId] = m | |
updateMember: (m) -> | |
return unless m | |
@addMember(m) | |
@updateState() | |
removeDuplicateMember: (org) -> | |
return unless org | |
aid = org.areaId | |
return if aid is 'friend' | |
oa = org.arcana | |
return unless oa | |
n1 = oa.name | |
n2 = org.chainArcana?.name || '' | |
@eachMembers (k, m) -> | |
return if k is 'friend' | |
return if k is aid | |
a = m.arcana | |
return unless a | |
if (a.name is n1 || a.name is n2) | |
m.deleteMember() | |
else if m.chainArcana | |
cn = m.chainArcana.name | |
if (cn is n1 || cn is n2) | |
m.unbindChain() | |
changeEditMode: (mode) -> | |
@editMode = mode | |
createCode: -> | |
header = "V#{ver}" | |
code = '' | |
@eachMembers (k, m) -> | |
if m?.arcana | |
code += m.arcana.jobCode | |
code += (if m.chainArcana then m.chainArcana.jobCode else 'N') | |
else | |
code += 'NN' | |
if (/^N+$/).test(code) then '' else (header + code) | |
# private | |
calcTotalCost = (ptm)-> | |
cost = 0 | |
for k in memberKeys | |
continue if k is 'friend' | |
m = ptm[k] | |
cost += m.chainedCost() if m | |
cost | |
PtEditView = React.createClass | |
getInitialState: -> | |
members: null | |
results: null | |
showError: false | |
pagerSize: 8 | |
componentDidMount: -> | |
Members.initMembers(@) | |
SearchResult.search({recently: 24}, @) | |
render: -> | |
state = @state | |
`<div> | |
<HeaderArea /> | |
<ErrorArea show={state.showError} /> | |
<EditArea members={state.members} /> | |
<TargetArea results={state.results} /> | |
</div>` | |
React.render `<PtEditView />`, document.getElementById('ptedit') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment