web and gui changes
This commit is contained in:
parent
7b37655531
commit
05ca633393
23 changed files with 305 additions and 232 deletions
|
@ -310,6 +310,27 @@ public class Audible implements IQueueListener<Book> {
|
|||
}
|
||||
}
|
||||
|
||||
// Look for books with missing info and re-parse if needed.
|
||||
// Information can be lost if
|
||||
boolean needSave = false;
|
||||
for (Book b:getBooks())
|
||||
{
|
||||
if (!b.has(BookElement.summary) && hasAAX(b))
|
||||
{
|
||||
task.setTask("Updating book information", "Reading "+b);
|
||||
needSave = AAXParser.instance.parseBook(b);
|
||||
}
|
||||
}
|
||||
|
||||
if (needSave)
|
||||
{
|
||||
try {
|
||||
save();
|
||||
} catch (IOException e) {
|
||||
LOG.error("Saving error..", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void updateFileCache() {
|
||||
|
@ -736,7 +757,7 @@ public class Audible implements IQueueListener<Book> {
|
|||
|
||||
if (audibleScraper != null)
|
||||
audibleScraper.logout();
|
||||
|
||||
AudibleScraper.deleteCookies();
|
||||
}
|
||||
|
||||
public String getAudibleURL() {
|
||||
|
|
|
@ -113,13 +113,33 @@ public class AudibleScraper {
|
|||
}
|
||||
|
||||
public void logout() {
|
||||
|
||||
ConnectionNotifier.getInstance().signout();
|
||||
|
||||
try {
|
||||
setURL("/signout");
|
||||
} catch(Throwable th)
|
||||
{
|
||||
LOG.info("signout error, ignorning...");
|
||||
|
||||
}
|
||||
CookieManager cm = getWebClient().getCookieManager();
|
||||
cm.clearCookies();
|
||||
File cookiesFile = Directories.META.getDir(cookiesFileName);
|
||||
if (cookiesFile.exists()) {
|
||||
cookiesFile.delete();
|
||||
}
|
||||
setLoggedIn(false);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static void deleteCookies()
|
||||
{
|
||||
File cookiesFile = Directories.META.getDir(cookiesFileName);
|
||||
if (cookiesFile.exists()) {
|
||||
cookiesFile.delete();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void saveCookies() throws IOException {
|
||||
|
|
|
@ -40,6 +40,10 @@ public class ConnectionNotifier extends EventNotifier<ConnectionListener> implem
|
|||
return out;
|
||||
}
|
||||
|
||||
public void signout()
|
||||
{
|
||||
state = State.SignedOut;
|
||||
}
|
||||
|
||||
public State getState() {
|
||||
return state;
|
||||
|
@ -58,14 +62,17 @@ public class ConnectionNotifier extends EventNotifier<ConnectionListener> implem
|
|||
// connected means in account
|
||||
// disconnected means a password is being asked for.
|
||||
enum State {
|
||||
Not_Connected, Connected, Disconnected
|
||||
Not_Connected, Connected, Disconnected, SignedOut
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void loginFailed(String url, String html) {
|
||||
for (ConnectionListener l : getListeners()) {
|
||||
l.loginFailed(url, html);
|
||||
|
||||
if (state!=State.SignedOut) {
|
||||
for (ConnectionListener l : getListeners()) {
|
||||
l.loginFailed(url, html);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -288,4 +288,20 @@ public class Book implements Comparable<Book>, Serializable {
|
|||
}
|
||||
|
||||
|
||||
|
||||
public String getPurchaseDateSortable() {
|
||||
String date = getPurchaseDate();
|
||||
if (!date.isEmpty()) {
|
||||
String dt[] = date.split("-");
|
||||
if (dt.length == 3) {
|
||||
return "20"+ dt[2] + "-" + dt[0] + "-" + dt[1]; // yyyy-mm-dd for sorting and viewing
|
||||
// warning, y3k bug
|
||||
} else
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return date;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -180,8 +180,10 @@ public abstract class GUI implements ITranslatable {
|
|||
|
||||
break;
|
||||
case linux:
|
||||
cmdLine.add("gnome-open");
|
||||
cmdLine.add("PATH");
|
||||
// gio open %s
|
||||
// gnome-open
|
||||
cmdLine.add("nautilus");
|
||||
cmdLine.add("--browser");
|
||||
break;
|
||||
}
|
||||
if (cmdLine.isEmpty()) return;
|
||||
|
@ -193,7 +195,7 @@ public abstract class GUI implements ITranslatable {
|
|||
p.run();
|
||||
|
||||
Results r = p.getResults();
|
||||
|
||||
logger.info(r.getErrorString());
|
||||
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
|
|
|
@ -301,12 +301,15 @@ public class AudibleGUI implements BookListener, ConnectionListener {
|
|||
}
|
||||
|
||||
public void convertMP3(Collection<Book> list) {
|
||||
bookNotifier.setEnabled(false);
|
||||
audible.convertQueue.addAll(list);
|
||||
bookNotifier.setEnabled(true);
|
||||
bookNotifier.booksUpdated();
|
||||
if (list.size() > 0) {
|
||||
bookNotifier.setEnabled(false);
|
||||
audible.convertQueue.addAll(list);
|
||||
bookNotifier.setEnabled(true);
|
||||
bookNotifier.booksUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean hasAAX(Book b) {
|
||||
return audible.hasAAX(b);
|
||||
}
|
||||
|
@ -421,16 +424,26 @@ public class AudibleGUI implements BookListener, ConnectionListener {
|
|||
msg = "You have " + dl.size() + " book(s) to download.\n";
|
||||
if (conv.size() != 0)
|
||||
msg = "You have " + conv.size() + " book(s) to convert to MP3\n";
|
||||
msg += "Would you like to start these job(s) now?";
|
||||
|
||||
LOG.info(msg + " autoConvert=" + prefs.autoConvert);
|
||||
if (prefs.autoConvert || prefs.autoDownload)
|
||||
{
|
||||
if (prefs.autoConvert)
|
||||
convertMP3(conv);
|
||||
if (prefs.autoDownload)
|
||||
downloadAAX(dl);
|
||||
|
||||
boolean ok = prefs.autoConvert;
|
||||
if (!ok) ok = MessageBoxFactory.showGeneralYesNo(null, "Start jobs?", msg);
|
||||
if (ok) {
|
||||
audible.convertQueue.addAll(conv);
|
||||
audible.downloadQueue.addAll(dl);
|
||||
} else {
|
||||
|
||||
msg += "Would you like to start these job(s) now?";
|
||||
|
||||
boolean ok = MessageBoxFactory.showGeneralYesNo(null, "Start jobs?", msg);
|
||||
if (ok) {
|
||||
convertMP3(conv);
|
||||
downloadAAX(dl);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -611,8 +624,11 @@ public class AudibleGUI implements BookListener, ConnectionListener {
|
|||
|
||||
PageBuilderTask task = new PageBuilderTask(destDir, list);
|
||||
ProgressDialog.doProgressTask(task);
|
||||
File index = new File(destDir, "index.html");
|
||||
File index = new File(destDir, "books.html");
|
||||
if (index.exists()) {
|
||||
|
||||
LOG.info("Book html file is: "+index.getAbsolutePath());
|
||||
|
||||
try {
|
||||
URI i = index.toURI();
|
||||
String u = i.toString();
|
||||
|
@ -621,6 +637,9 @@ public class AudibleGUI implements BookListener, ConnectionListener {
|
|||
} catch (Exception e) {
|
||||
showError(e, "displaying web page");
|
||||
}
|
||||
} else
|
||||
{
|
||||
assert(false);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
|
@ -837,7 +856,10 @@ public class AudibleGUI implements BookListener, ConnectionListener {
|
|||
public boolean logout() {
|
||||
SWTAsync.assertGUI();
|
||||
|
||||
if (browser != null && browser.isDisposed()) {
|
||||
if (browser != null && !browser.isDisposed()) {
|
||||
|
||||
String url = userPass.audibleRegion.getBaseURL()+"/signout";
|
||||
browser.setUrl(url);
|
||||
browser.close();
|
||||
}
|
||||
|
||||
|
@ -849,6 +871,7 @@ public class AudibleGUI implements BookListener, ConnectionListener {
|
|||
LOG.info("unable to set cookies: ", e);
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -929,6 +952,7 @@ public class AudibleGUI implements BookListener, ConnectionListener {
|
|||
public void jobCompleted(final ThreadedQueue<Book> queue, final IQueueJob job, final Book o) {
|
||||
booksUpdated();
|
||||
bookNotifier.bookUpdated(o);
|
||||
checkAutomation();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -954,9 +978,9 @@ public class AudibleGUI implements BookListener, ConnectionListener {
|
|||
final WebPage pageBuilder;
|
||||
final List<Book> books;
|
||||
|
||||
PageBuilderTask(File dest, final List<Book> list) {
|
||||
PageBuilderTask(File destDir, final List<Book> list) {
|
||||
super("Creating Your Audiobook Web Page");
|
||||
pageBuilder = new WebPage(dest, this);
|
||||
pageBuilder = new WebPage(destDir, this);
|
||||
books = list;
|
||||
}
|
||||
|
||||
|
@ -973,6 +997,26 @@ public class AudibleGUI implements BookListener, ConnectionListener {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// called after every book is downloaded or converted.
|
||||
public void checkAutomation()
|
||||
{
|
||||
ArrayList<Book> dl = audible.toDownload();
|
||||
ArrayList<Book> conv = audible.toConvert();
|
||||
|
||||
if (prefs.autoConvert)
|
||||
convertMP3(conv);
|
||||
if (prefs.autoDownload)
|
||||
downloadAAX(dl);
|
||||
|
||||
if (dl.size()==0 && conv.size()==0 && prefs.autoWebPage)
|
||||
{
|
||||
exportWebPage();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void load() throws IOException {
|
||||
Audible.instance.load();
|
||||
|
||||
|
@ -985,6 +1029,14 @@ public class AudibleGUI implements BookListener, ConnectionListener {
|
|||
prefs = gson.fromJson(content, Prefs.class);
|
||||
}
|
||||
|
||||
if (prefs.concurrentConversions<1||prefs.concurrentConversions>10)
|
||||
prefs.concurrentConversions = 5;
|
||||
if (prefs.concurrentDownloads<1||prefs.concurrentDownloads>10)
|
||||
prefs.concurrentDownloads = 3;
|
||||
|
||||
audible.convertQueue.setConcurrentJobs(prefs.concurrentConversions);
|
||||
audible.convertQueue.setConcurrentJobs(prefs.concurrentDownloads);
|
||||
|
||||
|
||||
} catch (Throwable th) {
|
||||
LOG.info("Error loading prefs", th);
|
||||
|
|
|
@ -3,4 +3,10 @@ package org.openaudible.desktop.swt.manager;
|
|||
// desktop app prefs.
|
||||
public class Prefs {
|
||||
public boolean autoConvert = true;
|
||||
public boolean autoDownload = false;
|
||||
public boolean autoWebPage = false;
|
||||
|
||||
int concurrentConversions = 3;
|
||||
int concurrentDownloads = 3;
|
||||
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ public class AppMenu implements ITranslatable, SelectionListener {
|
|||
private final Command[] actionCommands = {Command.ViewInAudible, Command.Show_MP3, Command.Play, Command.Download,
|
||||
Command.Convert, Command.Refresh_Book_Info};
|
||||
private final Command[] controlCommands = {Command.Connect, Command.Quick_Refresh, Command.Rescan_Library, Command.Download_All, Command.Convert_All,
|
||||
Command.MenuSeparator, Command.Browser}; // , Command.MenuSeparator, Command.Logout};
|
||||
Command.MenuSeparator, Command.Browser, Command.Logout}; // , Command.MenuSeparator, Command.Logout};
|
||||
|
||||
private final Command[] aboutCommands = {Command.Help, Command.AppWebPage, Command.Check_For_Update, Command.About};
|
||||
|
||||
|
|
|
@ -159,12 +159,8 @@ public class BookTable extends EnumTable<Book, BookTableColumn> implements BookL
|
|||
case Title:
|
||||
return b.getFullTitle();
|
||||
case Purchased:
|
||||
String date = b.getPurchaseDate();
|
||||
String dt[] = date.split("-");
|
||||
if (dt.length == 3) {
|
||||
return dt[2] + "-" + dt[0] + "-" + dt[1]; // yy-mm-dd for sorting and viewing
|
||||
}
|
||||
return date;
|
||||
return b.getPurchaseDateSortable();
|
||||
|
||||
default:
|
||||
assert (false);
|
||||
break;
|
||||
|
|
|
@ -2,7 +2,7 @@ package org.openaudible.desktop.swt.manager.views;
|
|||
|
||||
public enum BookTableColumn {
|
||||
File, Title, Author, Narrated_By, Time, Purchased;
|
||||
static int widths[] = {22, 250, 150, 150, 60, 60};
|
||||
static int widths[] = {22, 250, 150, 150, 60, 90};
|
||||
|
||||
// HasAAX, HasMP3,
|
||||
public static int[] getWidths() {
|
||||
|
|
|
@ -68,11 +68,12 @@ public class LogWindow {
|
|||
data = new GridData(GridData.FILL_BOTH);
|
||||
data.horizontalSpan = numCols;
|
||||
textView.setLayoutData(data);
|
||||
|
||||
commandLine = new Text(shell, SWT.SINGLE | SWT.BORDER);
|
||||
data = new GridData(GridData.VERTICAL_ALIGN_END);
|
||||
data.horizontalSpan = numCols;
|
||||
commandLine.setLayoutData(data);
|
||||
if (false) {
|
||||
commandLine = new Text(shell, SWT.SINGLE | SWT.BORDER);
|
||||
data = new GridData(GridData.VERTICAL_ALIGN_END);
|
||||
data.horizontalSpan = numCols;
|
||||
commandLine.setLayoutData(data);
|
||||
} else commandLine = null; // off.. not implemented
|
||||
|
||||
|
||||
shell.addListener(SWT.Close, event -> close());
|
||||
|
|
|
@ -26,7 +26,7 @@ public class Preferences extends Dialog {
|
|||
final String paths[] = new String[Directories.values().length];
|
||||
final Text dirText[] = new Text[dirs.length];
|
||||
Combo region;
|
||||
Button autoConvert;
|
||||
Button autoConvert, autoDownload, autoWebPage;
|
||||
|
||||
private Text email, password;
|
||||
private boolean pathsChanged = false;
|
||||
|
@ -75,6 +75,8 @@ public class Preferences extends Dialog {
|
|||
}
|
||||
|
||||
autoConvert.setSelection(AudibleGUI.instance.prefs.autoConvert);
|
||||
autoDownload.setSelection(AudibleGUI.instance.prefs.autoDownload);
|
||||
autoWebPage.setSelection(AudibleGUI.instance.prefs.autoWebPage);
|
||||
|
||||
|
||||
}
|
||||
|
@ -99,6 +101,8 @@ public class Preferences extends Dialog {
|
|||
}
|
||||
|
||||
AudibleGUI.instance.prefs.autoConvert = autoConvert.getSelection();
|
||||
AudibleGUI.instance.prefs.autoDownload = autoDownload.getSelection();
|
||||
AudibleGUI.instance.prefs.autoWebPage = autoWebPage.getSelection();
|
||||
|
||||
|
||||
if (pathsChanged) {
|
||||
|
@ -165,9 +169,18 @@ public class Preferences extends Dialog {
|
|||
Group group = c.newGroup("Automation", 1);
|
||||
GridData gd = new GridData(GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL);
|
||||
group.setLayoutData(gd);
|
||||
|
||||
autoDownload = GridComposite.newCheck(group, "Automatically download books");
|
||||
gd = new GridData(GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL);
|
||||
autoDownload.setLayoutData(gd);
|
||||
|
||||
autoConvert = GridComposite.newCheck(group, "Automatically convert to MP3");
|
||||
gd = new GridData(GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL);
|
||||
autoConvert.setLayoutData(gd);
|
||||
|
||||
autoWebPage = GridComposite.newCheck(group, "Automatically Update Web Page");
|
||||
gd = new GridData(GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL);
|
||||
autoWebPage.setLayoutData(gd);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -29,12 +29,12 @@ public class DownloadQueue extends ThreadedQueue<Book> {
|
|||
}
|
||||
|
||||
public boolean canAdd(Book b) {
|
||||
assert (b.has(BookElement.user_id));
|
||||
assert (b.has(BookElement.product_id));
|
||||
if (!super.canAdd(b)) return false;
|
||||
if (!b.has(BookElement.user_id)) return false;
|
||||
if (!b.has(BookElement.product_id)) return false;
|
||||
if (Audible.instance.hasAAX(b)) return false;
|
||||
if (!super.canAdd(b)) return false;
|
||||
if (!b.has(BookElement.user_id))
|
||||
return false;
|
||||
if (!b.has(BookElement.product_id))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ public class WebPage {
|
|||
final File webDir;
|
||||
final IProgressTask progress; // required
|
||||
int thumbSize = 200; // If changed, need to change html
|
||||
final static String indexName = "books.html";
|
||||
// final static String indexName = "books.html";
|
||||
|
||||
public WebPage(File dir, IProgressTask t) {
|
||||
webDir = dir;
|
||||
|
@ -43,7 +43,7 @@ public class WebPage {
|
|||
i.rating_count = b.get(BookElement.rating_count);
|
||||
i.audible = b.get(BookElement.infoLink);
|
||||
i.description = b.get(BookElement.description);
|
||||
i.purchased = b.get(BookElement.purchase_date);
|
||||
i.purchased = b.getPurchaseDateSortable();
|
||||
return i;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ import java.util.LinkedList;
|
|||
public abstract class ThreadedQueue<E> implements IQueueListener<E> {
|
||||
private static final Log LOG = LogFactory.getLog(ThreadedQueue.class);
|
||||
|
||||
final int concurrentJobs; // number of jobs that can be run at once
|
||||
int concurrentJobs; // number of jobs that can be run at once
|
||||
volatile boolean quit = false;
|
||||
int totalThreads = 0;
|
||||
|
||||
|
@ -43,6 +43,8 @@ public abstract class ThreadedQueue<E> implements IQueueListener<E> {
|
|||
return ok;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public int size() {
|
||||
return queue.size();
|
||||
}
|
||||
|
@ -281,5 +283,13 @@ public abstract class ThreadedQueue<E> implements IQueueListener<E> {
|
|||
|
||||
}
|
||||
|
||||
public int getConcurrentJobs() {
|
||||
return concurrentJobs;
|
||||
}
|
||||
|
||||
public void setConcurrentJobs(int concurrentJobs) {
|
||||
this.concurrentJobs = concurrentJobs;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ COMMAND_CONVERT=Convert to MP3
|
|||
COMMAND_CONVERT_ALL=Convert All to MP3
|
||||
COMMAND_COPY=Copy
|
||||
COMMAND_CUT=Cut
|
||||
COMMAND_DOWNLOAD=Download AAX
|
||||
COMMAND_DOWNLOAD=Download
|
||||
COMMAND_DOWNLOAD_ALL=Download All From Audible
|
||||
COMMAND_EXPORT_WEB_PAGE=Export Web Page
|
||||
COMMAND_FETCH_DECRYPTION_KEY=Fetch Decrypytion Key
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 114 B |
Binary file not shown.
Before Width: | Height: | Size: 114 B |
|
@ -1,50 +0,0 @@
|
|||
#container {
|
||||
width: 1300px;
|
||||
}
|
||||
|
||||
/* customize */
|
||||
|
||||
select.tidy_table {
|
||||
float: right;
|
||||
margin: 10px 0px 10px 0px;
|
||||
height:auto!important;
|
||||
color:#666; padding: 1%;
|
||||
font-size: 14px;
|
||||
font-weight: normal;
|
||||
word-wrap: break-word;
|
||||
text-align: left;
|
||||
|
||||
}
|
||||
|
||||
table.tidy_table {
|
||||
|
||||
white-space:normal;
|
||||
}
|
||||
|
||||
table.tidy_table th {
|
||||
white-space: wrap;
|
||||
}
|
||||
|
||||
table.tidy_table tr.check_on {
|
||||
background-color: #F7F7F7;
|
||||
}
|
||||
|
||||
table.tidy_table tr.check_off {
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
|
||||
table.tidy_table th {
|
||||
background-color: #DDDDDD;
|
||||
}
|
||||
|
||||
table.tidy_table th.sort_asc {
|
||||
background: #EEEEEE url( assets/arrow_asc.gif ) no-repeat right center;
|
||||
}
|
||||
|
||||
table.tidy_table th.sort_desc {
|
||||
background: #EEEEEE url( assets/arrow_desc.gif ) no-repeat right center;
|
||||
}
|
||||
|
||||
table.tidy_table td {
|
||||
border-top: 1px solid #CCCCCC;
|
||||
}
|
2
src/main/webapp/assets/jquery.min.js
vendored
2
src/main/webapp/assets/jquery.min.js
vendored
File diff suppressed because one or more lines are too long
9
src/main/webapp/assets/tidy-table.min.css
vendored
9
src/main/webapp/assets/tidy-table.min.css
vendored
|
@ -1,9 +0,0 @@
|
|||
/**
|
||||
* Tidy Table
|
||||
* Generate a sortable HTML table from JSON
|
||||
*
|
||||
* Copyright 2012-2015, Marc S. Brooks (http://mbrooks.info)
|
||||
* Licensed under the MIT license:
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
table.tidy_table{background-color:#FFFFFF;border-collapse:collapse;border:1px solid #CCCCCC;cursor:pointer;white-space:nowrap}table.tidy_table thead{border:none}table.tidy_table tr.check_on{background-color:#F5F5F5}table.tidy_table tr.check_off{background-color:#FFFFFF}table.tidy_table th{background-color:#DDD}table.tidy_table th.sort_asc{background:#EEEEEE url( images/arrow_asc.gif ) no-repeat right center}table.tidy_table th.sort_desc{background:#EEEEEE url( images/arrow_desc.gif ) no-repeat right center}table.tidy_table th,table.tidy_table td{padding:6px 20px 6px 20px}table.tidy_table td{border-right:1px solid #EEEEEE;padding:7px 20px 7px 20px}table.tidy_table th:nth-child(1),table.tidy_table td:nth-child(1){width:10px}table.tidy_table td:nth-child(1){border-right:1px solid #EEEEEE}table.tidy_table input[type=checkbox],table.tidy_table input[type=checkbox]{display:block;margin:0px auto 0px auto}table.tidy_table td:nth-last-child(1){border-right:none}table.tidy_table td{border-top:1px solid #CCCCCC}
|
9
src/main/webapp/assets/tidy-table.min.js
vendored
9
src/main/webapp/assets/tidy-table.min.js
vendored
|
@ -1,9 +0,0 @@
|
|||
/**
|
||||
* Tidy Table
|
||||
* Generate a sortable HTML table from JSON
|
||||
*
|
||||
* Copyright 2012-2015, Marc S. Brooks (http://mbrooks.info)
|
||||
* Licensed under the MIT license:
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('5(!V.B||(V.B&&19(V.B.1a.1B.W(\'.\',\'\'))<19(\'1.8.3\'.W(\'.\',\'\')))){1C 1D 1E(\'1F-1G 1H B 1.8.3 1I 1J.\');}(6($){4 r={"1b":6(c,d){4 e=$(u),2=e.2();4 f={1c:y,1d:y,1e:y};5(X.C>1){$.1f(f,c)}s{d=c}d=$.1f({K:6(a,b){5($.1K(a)){9 1L(b).W(/$|%|#/g,\'\')}}},d);5($.1M(2)){e.2({D:f,7:d})}9 e.v(\'Y\')},"1N":6(){$(u).1O()},"Y":6(l,m){4 n=$(u),2=n.2();4 o=$(\'<G></G>\').z(\'Z\');o.1P(6(){9 y});o.1Q(6(){9 y});4 p=$(\'<1g></1g>\'),E=$(\'<E></E>\');(6(){4 b=$(\'<F></F>\');H(4 i=0;i<2.7.1h.C;i++){4 c=2.7.1h[i];4 d=$(\'<L></L>\').t(c).M(\'1i\',c);b.t(d);4 e;5(!2.D.1e){5(m==\'N\'||!m){e=\'1j\';d.I=\'O\'}s{e=\'1k\';d.I=\'N\'}}s{5(m==\'O\'||!m){e=\'1j\';d.I=\'N\'}s{e=\'1k\';d.I=\'O\'}}5(l==i){d.z(e)}d.10(\'11\',{1l:i,1m:(l==i)?d.I:\'N\'},6(a){n.v(\'1n\',a.2.1l,a.2.1m)})}p.t(b)})();(6(){4 e=2.7.1o;H(4 j=0;j<e.C;j++){4 f=$(\'<F></F>\');H(4 k=0;k<e[j].C;k++){4 g=e[j][k];4 h=$(\'<P></P>\').t(g).M(\'1i\',g);f.t(h);5(2.7.w&&$.J(2.7.w.1p)){2.7.w.1p(h)}}E.t(f)}o.t(p);o.t(E);5(2.D&&2.D.1c){4 i=o.12(\'F\');i.13(6(b){4 c=$(\'<x></x>\').M(\'1R\',\'1q\');4 d;5(b===0){d=$(\'<L></L>\');c.10(\'11\',6(){n.v(\'14\',i)})}s{d=$(\'<P></P>\');c.10(\'11\',{1r:b},6(a){n.v(\'14\',i,a.2.1r)})}d.t(c);$(u).1S(d)})}})();5(2.7.w&&$.J(2.7.w.G)){2.7.w.G(o)}4 q=n.1T(\'G.Z\');5(q[0]){q.1U(o)}s{5(2.D&&2.D.1d){n.t(n.v(\'1s\',o,\'1V\'))}n.t(o)}9 o},"1s":6(c,d){4 e=$(u),2=e.2();4 f=$(\'<1t></1t>\').z(\'Z \'+d).1W(6(){4 a=$(u);4 b=2.7.15[a.1u()][1][\'1X\'];5($.J(b)){b(e.v(\'1v\',c))}a.1u(0)});$.13(2.7.15,6(a){4 b=$(\'<1w>\'+2.7.15[a][0]+\'</1w>\').M(\'1Y\',a);f.t(b)});5(2.7.w&&$.J(2.7.w.1x)){2.7.w.1x(f)}9 f},"1v":6(a){4 b=a.12(\'E > F\'),16=[];H(4 i=0;i<b.C;i++){4 c=b[i].1Z;5(c[0].20.A){4 d=[];H(4 j=1;j<c.C;j++){d[j-1]=c[j].21}16.22(d)}}9 16},"14":6(c,d){4 e=23;c.13(6(a){4 b=$(u),x=b.12(\':1q\').24();5(!d){5(a===0){e=(x.1y(\':A\'))?17:y;9}5(e){b.Q(\'R\').z(\'S\');x.T(\'A\',17)}s{b.Q(\'S\').z(\'R\');x.T(\'A\',y)}}s{5(a===0){9}5(x.1y(\':A\')){b.Q(\'R\').z(\'S\');x.T(\'A\',17)}s{b.Q(\'S\').z(\'R\');x.T(\'A\',y)}}})},"1n":6(d,e){4 f=$(u),2=f.2();5($.J(2.7.K)){4 g=(e==\'O\')?-1:1;2.7.1o.25(6(a,b){4 c=2.7.K(d,a[d]),U=2.7.K(d,b[d]);5(26(c)){9[g*18(c,U)]>[g*18(U,c)]?-1:1}s{9[g*1z(c,U)]}})}f.v(\'Y\',d,e)}};$.1a.v=6(a){5(r[a]){9 r[a].1A(u,27.28.29.2a(X,1))}s 5(2b a===\'2c\'||!a){9 r.1b.1A(u,X)}s{$.2d(\'2e \'+a+\' 2f 2g 2h 2i B.v\')}};6 18(a,b){9(a>b)?1:(a<b)?-1:0}6 1z(a,b){9 b-a}})(B);',62,143,'||data||var|if|function|config||return|||||||||||||||||||else|append|this|TidyTable|postProcess|input|false|addClass|checked|jQuery|length|settings|tbody|tr|table|for|order|isFunction|sortByPattern|th|attr|asc|desc|td|removeClass|check_off|check_on|prop|str2|window|replace|arguments|_createTable|tidy_table|on|click|find|each|_toggleSelRows|menuOptions|objs|true|cmpAny|parseInt|fn|init|enableCheckbox|enableMenu|reverseSortDir|extend|thead|columnTitles|title|sort_asc|sort_desc|col_number|sort_order|_sortByColumn|columnValues|column|checkbox|box_number|_createMenu|select|val|_getCheckedAsObj|option|menu|is|cmpInt|apply|jquery|throw|new|Error|Tidy|Table|requires|or|greater|trim|String|isEmptyObject|destroy|removeData|mousedown|mouseover|type|prepend|children|replaceWith|options|change|callback|value|childNodes|firstChild|textContent|push|null|first|sort|isNaN|Array|prototype|slice|call|typeof|object|error|Method|does|not|exist|in'.split('|'),0,{}));
|
|
@ -1,139 +1,138 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<script src="assets/jquery.min.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="assets/tidy-table.min.css">
|
||||
<link rel="stylesheet" type="text/css" href="assets/books.css">
|
||||
<script src="assets/tidy-table.min.js"></script>
|
||||
<script src="books.js" type="text/javascript"></script>
|
||||
|
||||
<!-- JavaScript insert start -->
|
||||
|
||||
<script>
|
||||
|
||||
$(document).ready(function() {
|
||||
if (false)
|
||||
{
|
||||
$.ajax({
|
||||
dataType: "json",
|
||||
url: "books.json",
|
||||
success: populateBooks
|
||||
});
|
||||
} else
|
||||
{
|
||||
populateBooks(window.myBooks);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
function renderTable(columnValues)
|
||||
{
|
||||
|
||||
$('#container')
|
||||
.TidyTable({
|
||||
enableCheckbox: false,
|
||||
enableMenu: false,
|
||||
reverseSortDir: false
|
||||
},
|
||||
{
|
||||
columnTitles: ['Link', 'Info', 'Summary'],
|
||||
columnValues: columnValues,
|
||||
menuOptions: [
|
||||
],
|
||||
postProcess: {
|
||||
table: resizeSummary,
|
||||
column: doColClick
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function trunc(str, len)
|
||||
{
|
||||
if (str===undefined) return "";
|
||||
return str.substring(0, len);
|
||||
}
|
||||
<meta charset="utf-8">
|
||||
|
||||
|
||||
function resizeSummary(table) {
|
||||
table.find('th:nth-child(2), td:nth-child(2)').css('width','200');
|
||||
}
|
||||
|
||||
function populateBooks(arr)
|
||||
{
|
||||
|
||||
var i;
|
||||
var out = [];
|
||||
|
||||
for(i = 0; i < arr.length; i++)
|
||||
{
|
||||
var book = arr[i];
|
||||
|
||||
var rating = book.rating_average = (book.rating_average !== undefined) ? book.rating_average:"";
|
||||
var author = book.author = (book.author !== undefined) ? trunc(book.author, 20):"";
|
||||
var narratedBy = book.narratedBy = (book.narratedBy !== undefined) ? trunc(book.narratedBy, 20):"";
|
||||
var run_time = book.run_time = (book.run_time !== undefined) ? book.run_time:"";
|
||||
var summary = trunc(book.description, 2048);
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-table/1.10.1/bootstrap-table.min.css">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/js/bootstrap.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-table/1.10.1/bootstrap-table.min.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="assets/books.css">
|
||||
<!-- Created by OpenAudible export web page. -->
|
||||
<script src="books.js" type="text/javascript"></script>
|
||||
|
||||
|
||||
summary = summary.replace(/(?:\r\n|\r|\n)/g, '<p />');
|
||||
|
||||
var thumb = "<img src='assets/download.jpg'>";
|
||||
|
||||
if (book.image !== undefined)
|
||||
thumb = "<img src='thumb/"+encodeURIComponent(book.image)+"' width='200' height='200'>"; // Thumbnail size
|
||||
|
||||
|
||||
var linkName = trunc(book.title, 90);
|
||||
var mp3 = encodeURIComponent(book.mp3);
|
||||
var thumbLink = "<a href='mp3/"+mp3+"'>"+thumb+"</a> ";
|
||||
<script>
|
||||
|
||||
var info = "<strong>"+trunc(book.title, 50)+"</strong><br>";
|
||||
|
||||
if (author.length>0)
|
||||
info += "by <i>"+author+"</i><br>";
|
||||
if (narratedBy.length>0)
|
||||
info += "Narrated by "+narratedBy+"<br>";
|
||||
info += run_time;
|
||||
info += " ";
|
||||
info += trunc(book.rating_average, 99);
|
||||
|
||||
var row = [thumbLink, info, summary];
|
||||
out.push(row);
|
||||
}
|
||||
|
||||
renderTable(out);
|
||||
|
||||
|
||||
}
|
||||
function filter() {
|
||||
var text = $("#filter").val();
|
||||
var rex = new RegExp(text, 'i');
|
||||
$('.searchable tr').hide();
|
||||
$('.searchable tr').filter(function () {
|
||||
return rex.test($(this).text());
|
||||
}).show();
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
populateBooks(window.myBooks);
|
||||
$('#filter').keyup(filter);
|
||||
});
|
||||
|
||||
|
||||
function trunc(str, len) {
|
||||
if (str === undefined) return "";
|
||||
return str.substring(0, len);
|
||||
}
|
||||
|
||||
|
||||
// post-process DOM elements
|
||||
function doTableClick(table) {
|
||||
table.on('hover', function() {
|
||||
// alert('doTableClick(table)');
|
||||
});
|
||||
}
|
||||
function resizeSummary(table) {
|
||||
table.find('th:nth-child(2), td:nth-child(2)').css('width', '200');
|
||||
}
|
||||
|
||||
function doColClick(col)
|
||||
{
|
||||
col.on('click', function() {
|
||||
// alert('doColClick(value=' + $(this).text() + ')');
|
||||
});
|
||||
}
|
||||
function populateBooks(arr) {
|
||||
|
||||
var i;
|
||||
var data = [];
|
||||
|
||||
for (i = 0; i < arr.length; i++) {
|
||||
var book = arr[i];
|
||||
|
||||
var rating = book.rating_average = (book.rating_average !== undefined) ? book.rating_average : "";
|
||||
var author = book.author = (book.author !== undefined) ? trunc(book.author, 20) : "";
|
||||
var narratedBy = book.narratedBy = (book.narratedBy !== undefined) ? trunc(book.narratedBy, 20) : "";
|
||||
var run_time = book.run_time = (book.run_time !== undefined) ? book.run_time : "";
|
||||
var summary = trunc(book.description, 2048);
|
||||
|
||||
|
||||
</script>
|
||||
summary = summary.replace(/(?:\r\n|\r|\n)/g, '<p />');
|
||||
|
||||
<title>OpenAudible collection of audiobooks</title>
|
||||
var thumb = "<img src='assets/download.jpg'>";
|
||||
|
||||
if (book.image !== undefined)
|
||||
thumb = "<img src='thumb/" + encodeURIComponent(book.image) + "' width='200' height='200'>"; // Thumbnail size
|
||||
|
||||
|
||||
var linkName = trunc(book.title, 90);
|
||||
var mp3 = encodeURIComponent(book.mp3);
|
||||
var thumbLink = "<a href='mp3/" + mp3 + "'>" + thumb + "</a> ";
|
||||
|
||||
var info = "<strong>" + trunc(book.title, 50) + "</strong><br>";
|
||||
|
||||
if (author.length > 0)
|
||||
info += "by <i>" + author + "</i><br>";
|
||||
if (narratedBy.length > 0)
|
||||
info += "Narrated by " + narratedBy + "<br>";
|
||||
info += run_time;
|
||||
info += " ";
|
||||
info += trunc(book.rating_average, 99);
|
||||
|
||||
var row = {};
|
||||
row['title'] = thumbLink;
|
||||
row['info'] = info;
|
||||
row['purchased'] = book.purchased;
|
||||
row['summary'] = summary;
|
||||
|
||||
data.push(row);
|
||||
}
|
||||
|
||||
$('#table').bootstrapTable({data: data});
|
||||
|
||||
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<title>OpenAudible collection of audiobooks</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
<div id="container"></div>
|
||||
<div id="container">
|
||||
<div class="row">
|
||||
<div class="col-md-4 col-md-offset-2">
|
||||
<div class="input-group">
|
||||
|
||||
<div class="input-group-btn">
|
||||
<button class="btn btn-default" type="submit"><i class="glyphicon glyphicon-search"></i></button>
|
||||
</div>
|
||||
<input type="text" class="form-control" placeholder="Search" name="srch-term" id="filter">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
|
||||
<table id="table" class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-field="title" data-sortable="true">Title</th>
|
||||
<th data-field="info" data-sortable="true">Info</th>
|
||||
<th data-field="purchased" data-sortable="true">Purchased</th>
|
||||
<th data-field="summary" data-sortable="false">Summary</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="searchable">
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
Loading…
Reference in a new issue