// // Copyright 2009 Robin Komiwes, Bruno Verachten, Christophe Cordenier // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package com.wooki.pages.chapter; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ConcurrentModificationException; import org.apache.commons.fileupload.FileUploadException; import org.apache.tapestry5.Block; import org.apache.tapestry5.EventConstants; import org.apache.tapestry5.annotations.AfterRender; import org.apache.tapestry5.annotations.Import; import org.apache.tapestry5.annotations.InjectComponent; import org.apache.tapestry5.annotations.InjectPage; import org.apache.tapestry5.annotations.OnEvent; import org.apache.tapestry5.annotations.Property; import org.apache.tapestry5.annotations.SessionState; import org.apache.tapestry5.annotations.SetupRender; import org.apache.tapestry5.corelib.components.Form; import org.apache.tapestry5.ioc.Messages; import org.apache.tapestry5.ioc.annotations.Inject; import org.apache.tapestry5.ioc.annotations.Symbol; import org.apache.tapestry5.json.JSONArray; import org.apache.tapestry5.json.JSONObject; import org.apache.tapestry5.services.Request; import org.apache.tapestry5.services.javascript.JavaScriptSupport; import org.apache.tapestry5.upload.services.UploadSymbols; import org.apache.tapestry5.util.TextStreamResponse; import com.ibm.icu.util.Calendar; import com.wooki.Draft; import com.wooki.Drafts; import com.wooki.base.ChapterBase; import com.wooki.domain.biz.ChapterManager; import com.wooki.domain.exception.PublicationXmlException; import com.wooki.links.PageLink; import com.wooki.links.impl.NavLink; import com.wooki.links.impl.ViewLink; /** * This page is used to update/publish a chapter of a given book. * * @author ccordenier */ @Import(library = { "context:/static/js/jquery.notifyBar.js", "context:/static/js/notifybar.js" }, stylesheet = { "context:/static/css/jquery.notifyBar.css" }) public class Edit extends ChapterBase { @Inject private ChapterManager chapterManager; @Inject private Block titleBlock; @Inject private Messages messages; @Inject private JavaScriptSupport jsSupport; @Inject private Request request; @InjectComponent private Form editChapterForm; @InjectPage private Index index; @Inject @Symbol(UploadSymbols.FILESIZE_MAX) private long maxFileSize; @SessionState private Drafts drafts; @Property private String data; @Property private Long previous; @Property private String previousTitle; @Property private Long next; @Property private String nextTitle; @Property private boolean abstractChapter; @Property private PageLink left; @Property private PageLink right; @Property private PageLink center; @Property private Draft draft; private DateFormat format = new SimpleDateFormat("hh:mm"); private boolean publish; private boolean cancel; @OnEvent(value = EventConstants.ACTIVATE) @Override public Object setupChapter(Long bookId, Long chapterId) { super.setupChapter(bookId, chapterId); draft = drafts.getOrCreate(getChapter()); return null; } @SetupRender public void prepareFormData() { // If currently edited then get it from user session, otherwise took content from db if (draft.getData() != null) { data = draft.getData(); } else { data = chapterManager.getLastContent(getChapterId()); } // Check if we are editing the abstract chapter if (getBook().getChapters() != null && getBook().getChapters().size() > 0 && getBook().getChapters().get(0).getId().equals(getChapterId())) { abstractChapter = true; } // Prepare previous and next links Object[] data = chapterManager.findPrevious(getBookId(), getChapterId()); if (data != null && data.length == 2) { previous = (Long) data[0]; previousTitle = (String) data[1]; } data = chapterManager.findNext(getBookId(), getChapterId()); if (data != null && data.length == 2) { next = (Long) data[0]; nextTitle = (String) data[1]; } } @SetupRender public void setupNav() { selectAdmin(0); if ((previous != null) && (previousTitle != null)) { left = new NavLink("chapter/index", "nav-left", previousTitle, getBookId(), previous); } else { left = new ViewLink("book/index", "toc", getBookId()); } if ((next != null) && (nextTitle != null)) { right = new NavLink("chapter/index", "nav-right", nextTitle, getBookId(), next); } center = new NavLink("book/index", "book-root", getBook().getTitle(), getBookId()); } @AfterRender public void setupJs() { this.jsSupport.addInitializerCall("initUpdateTitleFocus", new JSONObject()); } @OnEvent(value = EventConstants.SUCCESS, component = "updateTitle") public Object updateTitle() { chapterManager.update(getChapter()); return titleBlock; } @OnEvent(value = EventConstants.PASSIVATE) public Object[] retrieveIds() { return new Object[] { getBookId(), getChapterId() }; } /** * Used to check which submit button has been clicked */ public void onPublish() { publish = true; } /** * Used to check which submit button has been clicked */ public void onUpdate() { publish = false; } /** * Update content and publish if requested. * * @return The book index page */ @OnEvent(value = EventConstants.SUCCESS, component = "editChapterForm") public Object updateChapter() { draft.setData(data); // If autosave then save in session and return if (request.isXHR()) { JSONObject result = new JSONObject(); result.put("message", messages.format("autosave-success", format.format(Calendar .getInstance().getTime()))); return result; } try { if (!cancel) { chapterManager.updateContent(getChapterId(), draft); if (publish) { chapterManager.publishChapter(getChapterId()); } } index.setBookId(getBookId()); if (publish) { index.setupChapter(getBookId(), getChapterId()); } else { index.setupChapter(getBookId(), getChapterId(), ChapterManager.LAST); index.setRevision(ChapterManager.LAST); } // Clean session drafts.remove(getChapter()); return index; } catch (PublicationXmlException pxEx) { editChapterForm.recordError(messages.get("publication-exception")); return this; } catch (ConcurrentModificationException cmEx) { // Update the draft and inform the user draft.setTimestamp(getChapter().getLastModified()); editChapterForm.recordError(messages.get("concurrent-modification-exception")); return this; } } public Object[] getCancelCtx() { return new Object[] { getBookId(), getChapterId() }; } /** * Handle upload exception * * @param ex * @return */ public Object onUploadException(FileUploadException ex) { JSONObject result = new JSONObject(); JSONArray message = new JSONArray(); result.put("error", true); message.put(messages.format("upload-exception", maxFileSize / 1024)); result.put("messages", message); return new TextStreamResponse("text/html", result.toString()); } }