Load all data files from a single archive
This commit is contained in:
@@ -19,11 +19,11 @@ module.exports = class BaseModel extends Backbone.Model
|
||||
continue if name is 'id'
|
||||
Object.defineProperty this, name, get:makeGetter(name), set:makeSetter(name)
|
||||
|
||||
@fileCache = options.fileCache or null
|
||||
@loading = null
|
||||
@logEvents = options.logEvents or false
|
||||
@state = c.modelState.unloaded
|
||||
|
||||
@loading = null
|
||||
|
||||
Object.defineProperties this,
|
||||
isUnloaded: { get:-> @state is c.modelState.unloaded }
|
||||
isLoading: { get:-> @state is c.modelState.loading }
|
||||
@@ -60,13 +60,25 @@ module.exports = class BaseModel extends Backbone.Model
|
||||
|
||||
@state = c.modelState.loading
|
||||
@trigger c.event.request, this
|
||||
@loading = w.promise (resolve, reject)=>
|
||||
|
||||
loadFromServer = =>
|
||||
w.promise (resolve, reject)=>
|
||||
$.ajax
|
||||
url: url
|
||||
dataType: 'text'
|
||||
success: (text, status, xhr)=> resolve @onLoadSucceeded text, status, xhr
|
||||
error: (xhr, status, error)=> reject @onLoadFailed error, status, xhr
|
||||
|
||||
if @fileCache?
|
||||
@loading = @fileCache.loading.then =>
|
||||
if @fileCache.hasFile url
|
||||
@onLoadSucceeded @fileCache.getFile(url), 'success', {url:url}
|
||||
return w.resolve(true)
|
||||
else
|
||||
@loading = loadFromServer()
|
||||
else
|
||||
@loading = loadFromServer()
|
||||
|
||||
@loading.catch (e)-> # do nothing
|
||||
return @loading
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
###
|
||||
#
|
||||
# Crafting Guide - event_recorder.coffee
|
||||
#
|
||||
# Copyright (c) 2014-2015 by Redwood Labs
|
||||
# Copyright © 2014-2016 by Redwood Labs
|
||||
# All rights reserved.
|
||||
###
|
||||
#
|
||||
|
||||
util = require 'util'
|
||||
|
||||
|
||||
@@ -129,6 +129,7 @@ module.exports = class Mod extends BaseModel
|
||||
|
||||
@_modVersions.push modVersion
|
||||
@listenTo modVersion, c.event.change, => @trigger c.event.change, this
|
||||
modVersion.fileCache = this.fileCache
|
||||
modVersion.mod = this
|
||||
|
||||
@trigger c.event.add + ':modVersion', modVersion, this
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
#
|
||||
# Crafting Guide - file_cache.coffee
|
||||
#
|
||||
# Copyright © 2014-2016 by Redwood Labs
|
||||
# All rights reserved.
|
||||
#
|
||||
|
||||
########################################################################################################################
|
||||
|
||||
module.exports = class FileCache extends Backbone.Events
|
||||
|
||||
@::FILE_TOKEN = '#file='
|
||||
|
||||
constructor: (url)->
|
||||
@_ajax = $.ajax
|
||||
@_files = {}
|
||||
@_loading = w.resolve(true)
|
||||
|
||||
if url? then @loadArchive(url).catch(->)
|
||||
|
||||
# Public Methods ###############################################################################
|
||||
|
||||
getFile: (file)->
|
||||
return null unless @hasFile file
|
||||
return @_files[file]
|
||||
|
||||
hasFile: (file)->
|
||||
return @_files[file]?
|
||||
|
||||
loadArchive: (url)->
|
||||
if not _.isFunction(@_ajax) then throw new Error '$.ajax is required'
|
||||
|
||||
newLoading = w.promise (resolve, reject)=>
|
||||
@_ajax
|
||||
url: url
|
||||
dataType: 'text'
|
||||
success: (text, status, xhr)=> resolve @_onLoadSuccess text, status, xhr
|
||||
error: (xhr, status, error)=> resolve @_onLoadError error, status, xhr
|
||||
|
||||
@_loading = w.join @_loading, newLoading
|
||||
|
||||
# Property Methods #############################################################################
|
||||
|
||||
Object.defineProperties @prototype,
|
||||
|
||||
loading:
|
||||
get: -> return @_loading
|
||||
|
||||
# Private Methods ##############################################################################
|
||||
|
||||
_onLoadError: (error, status, xhr)->
|
||||
console.error "Failed to load archive: #{xhr.responseText}"
|
||||
return false
|
||||
|
||||
_onLoadSuccess: (text, status, xhr)->
|
||||
return @_parseArchive text
|
||||
|
||||
_parseArchive: (text)->
|
||||
file = null
|
||||
tokenIndex = nameStartIndex = nameEndIndex = fileStartIndex = fileEndIndex = 0
|
||||
fileCount = 0
|
||||
|
||||
while true
|
||||
tokenIndex = text.indexOf @FILE_TOKEN, fileStartIndex
|
||||
if tokenIndex is -1
|
||||
if file?
|
||||
@_files[file] = text.substring fileStartIndex, text.length
|
||||
fileCount += 1
|
||||
break
|
||||
|
||||
if file?
|
||||
fileEndIndex = tokenIndex - 1
|
||||
@_files[file] = text.substring fileStartIndex, fileEndIndex
|
||||
fileCount += 1
|
||||
|
||||
nameStartIndex = tokenIndex + @FILE_TOKEN.length
|
||||
nameEndIndex = text.indexOf '\n', nameStartIndex
|
||||
if nameEndIndex is -1
|
||||
file = text.substring nameStartIndex, text.length
|
||||
@_files[file] = ''
|
||||
break
|
||||
|
||||
file = text.substring nameStartIndex, nameEndIndex
|
||||
fileStartIndex = nameEndIndex + '\n'.length
|
||||
|
||||
return fileCount > 0
|
||||
@@ -0,0 +1,63 @@
|
||||
|
||||
FileCache = require './file_cache'
|
||||
|
||||
########################################################################################################################
|
||||
|
||||
describe 'file_cache.coffee', ->
|
||||
|
||||
beforeEach ->
|
||||
@cache = new FileCache
|
||||
|
||||
makeTestAjax = (text)->
|
||||
return (options)->
|
||||
options.success text, 'success', {url:options.url}
|
||||
|
||||
it 'can load an archive with a single file', ->
|
||||
@cache._ajax = makeTestAjax '#file=alpha\nbravo charlie delta'
|
||||
@cache.loadArchive 'http://test'
|
||||
.then =>
|
||||
@cache.hasFile('alpha').should.equal true
|
||||
@cache.getFile('alpha').should.equal 'bravo charlie delta'
|
||||
|
||||
it 'can load an archive with multiple files', ->
|
||||
@cache._ajax = makeTestAjax '#file=alpha\nbravo charlie\n#file=delta\necho foxtrot'
|
||||
@cache.loadArchive 'http://test'
|
||||
.then =>
|
||||
@cache.hasFile('alpha').should.equal true
|
||||
@cache.getFile('alpha').should.equal 'bravo charlie'
|
||||
@cache.hasFile('delta').should.equal true
|
||||
@cache.getFile('delta').should.equal 'echo foxtrot'
|
||||
|
||||
it 'can cope with an empty file in the middle of an archive', ->
|
||||
@cache._ajax = makeTestAjax '#file=alpha\nbravo charlie\n#file=delta\n#file=echo\nfoxtrot golf'
|
||||
@cache.loadArchive 'http://test'
|
||||
.then =>
|
||||
@cache.hasFile('alpha').should.equal true
|
||||
@cache.getFile('alpha').should.equal 'bravo charlie'
|
||||
@cache.hasFile('delta').should.equal true
|
||||
@cache.getFile('delta').should.equal '\n'
|
||||
@cache.hasFile('echo').should.equal true
|
||||
@cache.getFile('echo').should.equal 'foxtrot golf'
|
||||
|
||||
it 'can cope with an empty file at the end of an archive', ->
|
||||
@cache._ajax = makeTestAjax '#file=alpha\nbravo charlie\n#file=delta'
|
||||
@cache.loadArchive 'http://test'
|
||||
.then =>
|
||||
@cache.hasFile('alpha').should.equal true
|
||||
@cache.getFile('alpha').should.equal 'bravo charlie'
|
||||
@cache.hasFile('delta').should.equal true
|
||||
@cache.getFile('delta').should.equal ''
|
||||
|
||||
it 'can load multiple, non-overlapping archives', ->
|
||||
@cache._ajax = makeTestAjax '#file=alpha\nbravo charlie\n#file=delta\necho foxtrot'
|
||||
@cache.loadArchive 'http://test'
|
||||
|
||||
@cache._ajax = makeTestAjax '#file=golf\nhotel india'
|
||||
@cache.loadArchive 'http://test2'
|
||||
.then =>
|
||||
@cache.hasFile('alpha').should.equal true
|
||||
@cache.getFile('alpha').should.equal 'bravo charlie'
|
||||
@cache.hasFile('delta').should.equal true
|
||||
@cache.getFile('delta').should.equal 'echo foxtrot'
|
||||
@cache.hasFile('golf').should.equal true
|
||||
@cache.getFile('golf').should.equal 'hotel india'
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
BaseController = require './base_controller'
|
||||
FeedbackController = require './feedback/feedback_controller'
|
||||
FileCache = require '../models/site/file_cache'
|
||||
FooterController = require './footer/footer_controller'
|
||||
GitHubUser = require '../models/site/github_user'
|
||||
HeaderController = require './header/header_controller'
|
||||
@@ -26,8 +27,9 @@ module.exports = class SiteController extends BaseController
|
||||
super options
|
||||
|
||||
@client = options.client
|
||||
@fileCache = new FileCache c.url.modpackArchive()
|
||||
@imageLoader = new ImageLoader defaultUrl:'/images/unknown.png'
|
||||
@modPack = new ModPack
|
||||
@modPack = new ModPack {}, fileCache:@fileCache
|
||||
@router = new Router this
|
||||
@storage = options.storage
|
||||
|
||||
@@ -42,7 +44,7 @@ module.exports = class SiteController extends BaseController
|
||||
m.activeModVersion.fetch() if m.activeModVersion?
|
||||
|
||||
for modSlug, modData of c.defaultMods
|
||||
mod = new Mod slug:modSlug
|
||||
mod = new Mod {slug:modSlug}, {fileCache:@fileCache}
|
||||
mod.on c.event.change + ':activeModVersion', makeResponder mod
|
||||
@storage.register "mod:#{mod.slug}", mod, 'activeVersion', modData.defaultVersion
|
||||
mod.fetch()
|
||||
|
||||
@@ -138,6 +138,7 @@ url.login = _.template "/login"
|
||||
url.mod = _.template "/browse/<%= modSlug %>/"
|
||||
url.modData = _.template "/data/<%= modSlug %>/mod.cg"
|
||||
url.modIcon = _.template "/data/<%= modSlug %>/icon.png"
|
||||
url.modpackArchive = _.template "/data/modpack.cg"
|
||||
url.modVersionData = _.template "/data/<%= modSlug %>/versions/<%= modVersion %>/mod-version.cg"
|
||||
url.root = _.template "/"
|
||||
url.tutorial = _.template "/browse/<%= modSlug %>/tutorials/<%= tutorialSlug %>/"
|
||||
|
||||
Reference in New Issue
Block a user