@@ -80,7 +80,7 @@
Sign in to Book Editor
Places I have permission to make changes:
@@ -93,6 +93,32 @@
Places I have permission to make changes:
+
+
+
+ [Progress indicator here]
+
+
+
+
+
+
+
+ You already have a copy of this bookshelf.
+
+
+
diff --git a/scripts/gh-book/auth.coffee b/scripts/gh-book/auth.coffee
index 4cf38ebd..4703cb49 100644
--- a/scripts/gh-book/auth.coffee
+++ b/scripts/gh-book/auth.coffee
@@ -1,5 +1,6 @@
define [
'jquery'
+ 'underscore'
'marionette'
'cs!collections/content'
'cs!session'
@@ -10,7 +11,7 @@ define [
'cs!configs/github'
'bootstrapModal'
'bootstrapCollapse'
-], ($, Marionette, allContent, session, remoteUpdater, authTemplate, difflib, diffview, config) ->
+], ($, _, Marionette, allContent, session, remoteUpdater, authTemplate, difflib, diffview, config) ->
return class GithubAuthView extends Marionette.ItemView
template: authTemplate
@@ -25,6 +26,8 @@ define [
'click #show-diffs': 'showDiffsModal'
'submit #edit-repo-form': 'editRepo'
'click [data-select-repo]': 'selectRepo'
+ 'click #fork-book-modal .organisation-block': 'selectOrg'
+ 'click #fork-redirect-modal .btn-primary': 'selectFork'
'click [data-create-repo]': 'createRepo'
'shown #edit-repo-modal': 'createRepoModal'
@@ -77,18 +80,39 @@ define [
@isDirty = true
@render()
- signInModal: () ->
+ signInModal: (options) ->
$modal = @$el.find('#sign-in-modal')
# The hidden event on #login-advanced should not propagate
$modal.find('#login-advanced').on 'hidden', (e) => e.stopPropagation()
+ # We'll return a promise, and resolve it upon login or close.
+ promise = $.Deferred()
+ $modal.data('login-promise', promise)
+
# attach a close listener
- $modal.on 'hidden', () => @trigger 'close'
+ $modal.on 'hidden', () =>
+ if promise.state() == 'pending'
+ promise.reject()
+ @trigger 'close'
+
+ # Hide parts of the modal, if requested, for a simpler UI.
+ if options
+ if options.anonymous != undefined and options.anonymous == false
+ $modal.find('#login-anonymous').hide()
+ else
+ $modal.find('#login-anonymous').show()
+
+ if options.info != undefined and options.info == false
+ $modal.find('#login-info-wrapper').hide()
+ else
+ $modal.find('#login-info-wrapper').show()
# Show the modal
$modal.modal {show:true}
+ return promise
+
# Show a diff of all unsaved models
showDiffsModal: () ->
$modal = @$el.find('#diffs-modal')
@@ -134,17 +158,97 @@ define [
$modal.modal {show:true}
- forkContent: () ->
+ organisationModal: (info, orgs) ->
+ $modal = @$el.find('#fork-book-modal')
+ $body = $modal.find('.modal-body').empty()
- if not (@model.get('password') or @model.get('token'))
- alert 'Please Sign In before trying to fork a book'
- return
+ # Own account
+ $block = $('
')
+ $avatar = $('
![avatar]()
').attr('src', info.avatar_url)
+ $name = $('
').html(info.login)
+ $block.append($avatar).append($name).data('org-name', info.login)
+ $body.append($block)
+ for org in orgs
+ $block = $('')
+ $avatar = $('
').attr('src', org.avatar_url)
+ $name = $('').html(org.login)
+ $block.append($avatar).append($name).data('org-name', org.login)
+ $body.append($block)
- @model.getClient().getLogin().done (login) =>
- @model.getRepo()?.fork().done () =>
- @model.set 'repoUser', login
+ $modal.modal {show:true}
-
+ selectOrg: (e) ->
+ $block = $(e.target).addBack().closest('.organisation-block')
+ org = $block.data('org-name') or null
+ @$el.find('#fork-book-modal').modal('hide')
+ @__forkContent(org)
+
+ selectFork: (e) ->
+ e.preventDefault()
+ login = @$el.find('#fork-redirect-modal').modal('hide').data('login')
+ @_selectRepo(login, @model.get('repoName'))
+
+ forkContent: () ->
+ if not (@model.get('password') or @model.get('token'))
+ @signInModal
+ anonymous: false
+ info: false
+ .done () => @_forkContent()
+ return
+ @_forkContent()
+
+ _forkContent: () ->
+ # If user has more than one organisation, ask which one.
+ @model.getClient().getUser().getInfo().done (userinfo) =>
+ @model.getClient().getUser().getOrgs().done (orgs) =>
+ if orgs.length > 1
+ @organisationModal(userinfo, orgs)
+ else
+ @__forkContent(userinfo.login)
+
+ __forkContent: (login) ->
+ # If repo exists, go to it or cancel. Else fork.
+ @model.getClient().getRepo(login, @model.get('repoName')).getInfo().done () =>
+ @$el.find('#fork-redirect-modal').data('login', login).modal
+ show: true
+ .fail () =>
+ @___forkContent(login)
+
+ ___forkContent: (org) ->
+ $modal = @$el.find('#fork-progress-modal')
+ $body = $modal.find('.modal-body')
+ $body.html('Creating a Fork...')
+ $modal.modal {show: true}
+
+ # If the chosen organisation is myself, leave it out.
+ @model.getRepo()?.fork(org != @model.get('id') and org or null).done () =>
+ $body.html('Waiting for Fork to become available...')
+
+ # Change upstream repo
+ wait = 2000
+ @model.set 'repoUser', org
+
+ # Poll until repo becomes available
+ pollRepo = () =>
+ @model.getRepo()?.getInfo().done (info) =>
+ require ['backbone', 'cs!controllers/routing'], (bb, controller) =>
+ # Filter out the view bit, then set the url to reflect the fork
+ v = RegExp('repo/[^/]*/[^/]*(/branch/[^/]*)?/(.*)').exec(
+ bb.history.getHash())[2]
+ controller.trigger 'navigate', v
+ .fail () =>
+ if wait < 30
+ setTimeout(pollRepo, wait)
+ wait = wait * 2 # exponential backoff
+ else
+ alert('Fork failed')
+ .always () =>
+ # Leave it open for another two seconds, because sometimes
+ # the fork happens so quickly that people are unnerved by
+ # the flashing modal they couldn't read.
+ window.setTimeout((() -> $modal.modal('hide')), 2000)
+ pollRepo()
+
signIn: (e) ->
# Prevent form submission
@@ -156,6 +260,9 @@ define [
token: @$el.find('#github-token').val()
password: @$el.find('#github-password').val()
+ # signInModal persists the promise on the modal
+ promise = @$el.find('#sign-in-modal').data('login-promise')
+
if not (attrs.password or attrs.token)
alert 'We are terribly sorry but github recently changed so you must login to use their API.\nPlease refresh and provide a password or an OAuth token.'
else
@@ -166,6 +273,7 @@ define [
# The 1st time the editor loads up it waits for the modal to close
# but `render` will hide the modal without triggering 'close'
@trigger 'close'
+ promise.resolve()
.fail (err) =>
alert 'Login failed. Did you use the correct credentials?'
diff --git a/scripts/gh-book/gh-book.less b/scripts/gh-book/gh-book.less
index 6b532c88..7060ce1e 100755
--- a/scripts/gh-book/gh-book.less
+++ b/scripts/gh-book/gh-book.less
@@ -218,3 +218,16 @@ nav#workspace-sidebar-toc{
font-size: 120%;
}
}
+
+#fork-book-modal {
+ .organisation-block {
+ cursor: pointer;
+ img {
+ height: 45px;
+ width: 45px;
+ }
+ span {
+ margin-left: 0.5em;
+ }
+ }
+}