Commit b489e3c5 authored by François Billioud's avatar François Billioud

implement multi-user and multi-storage

parent 3f423885
......@@ -215,7 +215,7 @@ div.header-right div.input a {
border: 1px solid #D1D1D1;
display: none;
}
.action_menu ul li ul hover {
.action_menu ul li ul:hover {
display: block;
}
.action_menu ul li ul li:hover {
......@@ -330,7 +330,7 @@ div.gadget-action input#upload {
border: 1px solid #BBBBBB;
border-radius: 4px 4px 4px 4px;
color: #333333;
left: 1em;
left: 0.5em;
position: relative;
top: 0.1em;
}
......@@ -409,12 +409,46 @@ button.delete {
margin-left: 6px;
margin-top: 6px;
}
/* navigation buttons */
div.listbox-navigation {
float: right;
font-size: 13px;
margin-right: 5px;
margin-top: 6px;
margin-top: 0;
min-width: 10%;
display: none;
}
div.listbox-navigation input {
margin-top: 0.3em;
height: 18px;
width: 20px;
}
div.listbox-navigation button.listbox_first_page {
background-image: url("../images/ung/first_page.png");
}
div.listbox-navigation button.listbox_previous_page {
background-image: url("../images/ung/previous_page.png");
}
div.listbox-navigation button.listbox_next_page {
background-image: url("../images/ung/next_page.png");
}
div.listbox-navigation button.listbox_last_page {
background-image: url("../images/ung/last_page.png");
}
div.listbox-navigation button.listbox_previous_page, div.listbox-navigation button.listbox_next_page {
margin: 0;
width: 12px;
}
div.listbox-navigation button {
position: relative;
top: -0.2em;
background-repeat: no-repeat;
border: 0 none;
height: 20px;
display: none;
}
div.listbox-navigation button:hover {
cursor: pointer;
}
/* header */
......@@ -558,6 +592,10 @@ div#advertisement img{
height: 10em;
}
/* login table */
span#id_provider_details {
font-size: 8px;
float: left;
}
table#field_table, table#new-account-table, table#create-new-user {
border: 1px solid #C3D9FF;
width: 78%;
......@@ -606,6 +644,23 @@ div.footer a {
margin-right: 0.5em;
}
/**********************************************************
******************** tooltip area *********************/
span.tooltipElement {
cursor: pointer;
color: #0099CC;
}
div.toolLocation{
visibility: hidden;
position: absolute;
border-radius: 10px 10px 10px 10px;
border: 1px solid Black;
padding: 10px;
font-family: Verdana, Arial;
font-size: 10px;
background-color: #FFFFCC;
}
/**********************************************************
******************* dialog box ************************/
div.ui-dialog {
......@@ -624,9 +679,6 @@ div.ui-dialog-titlebar {
border-radius: 1px 1px 1px 1px;
height: 15px;
}
div.ui-dialog-titlebar {
height: 15px;
}
span#ui-dialog-title-edit_document, span#ui-dialog-title-upload_document, span#ui-dialog-title-gadget-listbox {
color: #222222 !important;
font: bold 12pt Arial,Sans-serif;
......@@ -658,4 +710,4 @@ div#edit_document {
}
span.ui-button-text {
font-size: 12px;
}
\ No newline at end of file
}
* Decision of JS pattern used for Prototypical Inheritance
* Desicion: Why meta-data should be inside the data of the file
** I had two choices about meta data:
*** Let the meta-data stay inside the data itself i.e. your data on file will contain the meta data too.
**** Advantage is that the ability to store meta-data is not needed or is dependednt on the type of storage
**** We have more control over the meta data and how it is interfaced.
**** Thus, currently meta-data in DAV is stored along with data, this way the hash returns the sum of both meta-data and data
**** This might be desirable or undesirable but good thing is that decision is in our hand
**** Other software must know how JIO stores the meta-data
*** Let the meta-data be separate from the data so that the server can take care of meta-data in meaningful way
**** This way, meta-data interface has to be written for every backend separately
**** We just work on the data, the hash is returned for only the data part. encryption (or other transformations) are done for only the data part
**** Many backend like ObjStore won't have meta-data handling in an intutive way
**** server will handle the meta-data
**** This facilitates JIO interaction with other services (eg: in Google Doc, if you use its API to do the meta-data, even Google Doc can use that information)
*** Decision
Meta-data with file data for now. Since JIO is open standard, we will publish our meta-data storing syntax. This way JIO can be used uniformally on All backends
The consequence of this is that we don't see meta-data as a different data, it is part of the document
* Object based Storage
** The basic idea is to let a object represent the entire tree of the
virtual file system
** The such objects can be nested inside each other. Hence to create
an entire filesystem is possible.
** Each object can be either a document (as are files in Unix) or a
collection (as are directory in Unix)
** We can then encapsulate the entire filesystem tree in as a single
object.
** The good part is that we can run JSON stringify on this object to
convert it into pure string and thus serialize it.
** The design should be such that these objects must be pluggable
inside other objects.
** Should be able to store Metadata
** Design
*** Each Object contain two basic information : doc_id, content
*** doc_id is basically the name of the resource (resource is a general term used for a collection or a document)
*** In a given collection, all the containing collections and document should have unique doc_id (i.e. you can't have a collection and a document named `foo' inside on collection)
*** Identification of if the resource is a collection or document is done by noting the type of the content, if it is an array, then the given resource is a collection, document otherwise
*** Any resource is identified by it's doc_id and parent object (or parent's doc_id, which itself is identified by using its parents doc_id)
***
** If the loadDocument requests a directory, (aka collection), return the hash is the sum of all the content inside that collection and let the data be an array with the docid of all the child documents.
** Implementing
** Current implmentation doesn't enjoy much of code-reuse, I think I can use more inheritance core-reuse, will have to refactor the code. But the basic design of JIO will facilitate that
......@@ -9,6 +9,8 @@ languages = ["fr","en"];
var availableLanguages = $("#available_languages");
currentPage = null;
currentDocument = null;
currentStorage = null;
/*
......@@ -23,7 +25,7 @@ var Page = function(page) {
this.editor = null;
//define as current page
currentPage = this;
if(page!=undefined) {this.loadXML("xml/"+page+".xml");}
if(page!="ung" && page !=undefined) {this.loadXML("xml/"+page+".xml");}
}
Page.prototype = {
setXML: function(data) {
......@@ -31,6 +33,7 @@ Page.prototype = {
this.loadPage();
},
//getters
getName: function() {return this.name;},
getXML: function() {return this.xml;},
getHTML: function() {return this.html;},
getTitle: function() {return $(this.getXML()).find("title").text();},
......@@ -52,7 +55,7 @@ Page.prototype = {
var dependencies = this.getDependencies();
$(dependencies).find("linkfile").each(function() {currentPage.include($(this).text(),"link");});//includes css
$(dependencies).find("scriptfile").each(function() {currentPage.include($(this).text(),"script");});//includes js
var doc = null;
var editor = null;
/* load the editor to work with and a new document to work on */
......@@ -112,7 +115,7 @@ Page.prototype = {
for (var i = 0; i<languages.length; i++) {
var l = languages[i];
if(l==user.getLanguage()) {$("span#current_language").html(l);}
if(l==user.getSetting("language")) {$("span#current_language").html(l);}
else {
avLang = avLang + "<li><span onclick='changeLanguage($(this).html())' id='" +l+ "'>"+l+"</span></li>\n"
}
......@@ -129,7 +132,7 @@ Page.prototype = {
$("a#document_title").html(title);
},
displayDocumentContent: function(doc) {this.getEditor().loadContentFromDocument(doc);},
displayDocumentState: function(doc) {$("a#document_state").html(doc.getState()[getCurrentUser().getLanguage()]);},
displayDocumentState: function(doc) {$("a#document_state").html(doc.getState()[getCurrentUser().getSetting("language")]);},
//web page information
displayPageTitle: function() {$("title#page_title").html(this.getTitle());},
......@@ -144,39 +147,205 @@ setCurrentPage = function(page) {currentPage = page;}
* @param arg : a json User object to load
*/
var User = function(arg) {
if(arg) {this.load(arg);}
if(arg) {
this.load(arg);
if(window.DocumentList) {this.documentList = new DocumentList(arg.documentList);}
}
else {
this.name = "unknown";
this.language = "en";
this.storage = "http://www.unhosted-dav.com";
this.identityProvider = "http://www.webfinger.com";
this.displayPreferences = 15;//number of displayed document in the list
this.name = "UNG";//default name
this.settings = {
language: "en",
displayPreferences: 15//number of displayed document in the list
}
this.documentList = new DocumentList();
this.documents = {};
}
}
User.prototype = new UngObject();//inherits from UngObject
User.prototype.load({//add methods thanks to the UngObject.load method
getName: function() {return this.name;},
setName: function(newName) {this.name = newName;},
getLanguage: function() {return this.language;},
setLanguage:function(language) {this.language = language;},
getStorageLocation: function() {return this.storage;},
setStorageLocation: function(storage) {this.storage = storage;},
getIdentityProvider: function() {return this.identityProvider;},
setIdentityProvider: function(IDProv) {this.identityProvider = IDProv;},
getDisplayPreferences: function() {return this.displayPreferences;},
setDisplayPreferences: function(n) {this.displayPreferences = n;},
getSetting: function(key) {return this.settings[key];},
setSetting: function(key,value) { this.settings[key] = value; },
getSettings: function() {return this.settings;},
getDocumentList: function() {return this.documentList;},
setDocumentList: function(list) {this.documentList = list;},
setAsCurrentUser: function() {
getCurrentPage().displayUserName(this);
getCurrentPage().displayLanguages(this);
setCurrentUser(this);
getCurrentStorage().setUser(this);
if(getCurrentPage().getName()=="ung") getDocumentList().setAsCurrentDocumentList();
}
});
getCurrentUser = function() {
return new User(JSON.parse(localStorage.getItem("currentUser")));
return getCurrentStorage().getUser();
}
/**
* Class Storage
* this class provides usual API to save/load/delete documents
* @param type : "local" to save in localStorage, or "JIO" for remote storage
* @param userName : the name of the user concerned by this storage
*/
var Storage = function(type, userName) {
this.type = type;
if(userName) {
var loaded = this.loadUser(userName)//load an existing user
if(!loaded) {//create a new user if there was no such one
var user = new User();
user.setName(userName);
this.setUser(user);
}
}
}
Storage.prototype = new UngObject();
Storage.prototype.load({
getType: function() {return this.type;},
getUser: function() {return this.user;},
loadUser: function(userName) {},
setUser: function(user) {this.user = user},
getDocument: function(address, instruction) {},
saveDocument: function(doc, address, instruction) {},
deleteDocument: function(address, instruction) {}
});
/**
* Class LocalStorage
* this class provides usual API to save/load/delete documents on the localStorage
*/
var LocalStorage = function(userName) {
Storage.call(this,"local", userName);
if(this.user) {
//this.user.documents = {}
//this.updateUser();
}
}
setCurrentUser = function(user) {localStorage.setItem("currentUser", JSON.stringify(user));}
LocalStorage.prototype = new Storage();
LocalStorage.prototype.load({
/* try to load the user information in the storage and save it in the
* storage instance.
* @param userName : the name of the user
* @return : true if the user existed and has been loaded, false otherwise
*/
loadUser: function(userName) {
try{
if(!localStorage[userName]) {throw "noSuchUser";}
this.user = new User(JSON.parse(localStorage[userName]));
return true;
} catch(e) {
if(e!="noSuchUser") {alert(e);}
return false
}
},
getUser: function() {return this.user;},
setUser: function(user) {
this.user = user;
localStorage[this.user.name] = JSON.stringify(user);
},
updateUser: function() {localStorage[this.user.name] = JSON.stringify(this.user);},
getDocument: function(address, instruction) {
var doc = new JSONDocument(this.user.documents[address]);
if(instruction) instruction(doc);
return doc;
},
saveDocument: function(doc, address, instruction) {
this.user.documents[address] = doc;
this.updateUser();
if(instruction) instruction();
},
deleteDocument: function(address, instruction) {
delete this.user.documents[address];
this.updateUser();
if(instruction) instruction();
},
save: function() {
this.updateUser();
localStorage.setItem("currentStorage", JSON.stringify(this));
}
});
/**
* Class JIOStorage
* this class provides usual API to save/load/delete documents on a remote storage
*/
var JIOStorage = function(userName) {
Storage.call(this,"JIO", userName);
}
JIOStorage.prototype = new Storage();
JIOStorage.prototype.load({
loadUser: function(userName) {
//JIO : IDProvider
},
getDocument: function(address, instruction) {
$.ajax({
url: address,
type: "GET",
dataType: type,
success: instruction,
error: function(type) {alert("Error "+type.status+" : fail while trying to load "+address);}
});
},
saveDocument: function(content, address, instruction) {
this.user.documents[address] = doc;
$.ajax({
url: address,
type: "PUT",
dataType: "json",
data: JSON.stringify(content),
headers: {Authorization: "Basic "+btoa("smik:asdf")},
fields: {withCredentials: "true"},
success: instruction,
error: function(type) {
if(type.status==201 || type.status==204) {instruction();}//ajax thinks that 201 is an error...
}
});
},
deleteDocument: function(address, instruction) {
delete this.user.documents[address];
$.ajax({
url: address,
type: "DELETE",
headers: {Authorization: "Basic "+btoa("smik:asdf")},
fields: {withCredentials: "true"},
success: instruction,
error: function(type) {
alert(type.status);//ajax thinks that 201 is an error...
}
});
}
});
getCurrentStorage = function() {
if(!currentStorage) {//if storage has not been loaded yet
var dataStorage = JSON.parse(localStorage.getItem("currentStorage"));
if(!dataStorage) {window.location = "login.html";return null;}//if it's the first connexion
switch(dataStorage.type) {//load the last storage used
case "local": currentStorage = new LocalStorage(); break;
case "JIO": currentStorage = new JIOStorage(); break;
}
currentStorage.loadUser(dataStorage.user.name);
currentStorage.type = dataStorage.type;
}
return currentStorage;
}
setCurrentStorage = function(storage) {
currentStorage = storage;
localStorage.setItem("currentStorage", JSON.stringify(storage));
}
......@@ -193,7 +362,7 @@ setCurrentUser = function(user) {localStorage.setItem("currentUser", JSON.string
var JSONDocument = function(arg) {
if(arg) {this.load(arg);}
else {
this.language = getCurrentUser().getLanguage();
this.language = getCurrentUser().getSetting("language");
this.version = null;
this.author=getCurrentUser().getName();
......@@ -211,7 +380,7 @@ JSONDocument.prototype.load({//add methods thanks to the UngObject.load method
//type
getType: function() {return this.type;},
setType: function(newType) {this.type = newType;},
//version
getVersion: function() {return this.version;},
setVersion: function(version) {this.version = version;},
......@@ -249,9 +418,9 @@ JSONDocument.prototype.load({//add methods thanks to the UngObject.load method
save: function(instruction) {
var doc = this;
saveFile(getDocumentAddress(this), doc, instruction);
getCurrentStorage().saveDocument(doc, getDocumentAddress(this), instruction);
},
remove: function(instruction) {deleteFile(getDocumentAddress(this), instruction);}
remove: function(instruction) {getCurrentStorage().deleteDocument(getDocumentAddress(this), instruction);}
});
JSONDocument.prototype.states = {
draft:{"fr":"Brouillon","en":"Draft"},
......@@ -259,9 +428,20 @@ JSONDocument.prototype.states = {
deleted:{"fr":"Supprimé","en":"Deleted"}
}
getCurrentDocument = function() {
return new JSONDocument(JSON.parse(localStorage.getItem("currentDocument")));
if(!currentDocument) {
currentDocument = new JSONDocument(JSON.parse(localStorage.getItem("currentDocument")));
}
return currentDocument;
}
setCurrentDocument = function(doc) {localStorage.setItem("currentDocument",JSON.stringify(doc));}
setCurrentDocument = function(doc) {
currentDocument = doc;
localStorage.setItem("currentDocument",JSON.stringify(doc));
}
supportedDocuments = {"text":{editorPage:"text-editor",icon:"images/icons/document.png"},
"illustration":{editorPage:"image-editor",icon:"images/icons/svg.png"},
......@@ -269,7 +449,9 @@ supportedDocuments = {"text":{editorPage:"text-editor",icon:"images/icons/docume
"other":{editorPage:null,icon:"images/icons/other.gif"},
undefined:{editorPage:null,icon:"images/icons/other.gif"}
}
getDocumentAddress = function(doc) {return "dav/"+doc.getCreation();}
getDocumentAddress = function(doc) {
return getCurrentStorage().getType()=="local" ? doc.getCreation() : "dav/"+doc.getCreation();
}
/*************************************************
****************** actions ******************
......@@ -300,6 +482,30 @@ editDocumentSettings = function() {
}
}
});
$("p#more_properties") .click(function(){
$("div#more_property").show();
$("p#hide_properties").show();
$("div#edit_document fieldset").animate({"height": "186px"}, "slow");
$("div.ui-dialog").animate({"top": "50px"}, "slow")
.animate({"height": "255px"}, "slow");
$("div#edit_document").animate({"height": "183px"}, "slow");
$("div#edit_document fieldset input").css("margin", "0")
.css("width", "60%");
$("div#edit_document fieldset label").css("float", "left")
.css("width", "35%");
$("div#more_property input").css("width", "47%");
$("p#more_properties").hide();
});
$("p#hide_properties") .click(function(){
$("div#more_property").hide();
$("p#more_properties").show();
$("p#hide_properties").hide();
$("div#edit_document fieldset input").css("width", "95%")
.css("margin-top", "14px");
$("div#edit_document fieldset").animate({"height": "69px"}, "slow");
$("div.ui-dialog").animate({"height": "148px"}, "slow");
$("div#edit_document").animate({"height": "78px"}, "slow");
});
}
)}
......@@ -353,6 +559,26 @@ gadgetListBox = function() {
});
}
/**
* open a dialog box to propose settings
*/
editUserSettings = function() {
$("div#preference_dialog").dialog({
autoOpen: false,
height: 215,
width: 319,
modal:true,
buttons: {
"Save": function(){
},
Cancel: function() {
$(this).dialog("close");
}
}
});
}
saveCurrentDocument = function() {
getCurrentPage().getEditor().saveEdition();
......@@ -364,7 +590,7 @@ saveCurrentDocument = function() {
* @param doc : the document to edit
*/
var startDocumentEdition = function(doc) {
loadFile(getDocumentAddress(doc),"json",function(data) {
getCurrentStorage().getDocument(getDocumentAddress(doc), function(data) {
doc.load(data);
setCurrentDocument(doc);
if(supportedDocuments[doc.getType()].editorPage) {window.location = "theme.html";}
......@@ -381,12 +607,18 @@ var stopDocumentEdition = function() {
* @param language : the new language
*/
var changeLanguage = function(language) {
var user = getCurrentUser();
user.setLanguage(language);
setCurrentUser(user);
getCurrentUser().setSetting("language");
getCurrentStorage().save();
getCurrentPage().displayLanguages(user);
window.location.reload();
}
var signOut = function() {
delete localStorage.currentStorage;
delete localStorage.currentDocumentID;
window.location = "login.html";
}
cancel_sharing = function() {alert("cancel");}
translate = function() {alert("translate");}
submit = function() {alert("submit");}
......
......@@ -92,7 +92,7 @@ List.prototype.load({
return this.tail().get(i-1);
},
set: function(i,element) {
if(i>=this.size()) {error("set out of bounds, "+i+" : "+this.size(),this);return}
if(i>=this.size()) {errorMessage("set out of bounds, "+i+" : "+this.size(),this);return}
if(i==0) {
this.headElement=element;
} else {
......@@ -100,7 +100,7 @@ List.prototype.load({
}
},
remove: function(i) {
if(i>=this.size()) {error("remove out of bounds, "+i+" : "+this.size(),this);return}//particular case
if(i>=this.size()) {errorMessage("remove out of bounds, "+i+" : "+this.size(),this);return}//particular case
if(i==0) {this.pop();return}//particular case
if(i==1) {//init
this.previous = this.tail().tail();
......@@ -110,7 +110,7 @@ List.prototype.load({
this.length--;
},
pop: function() {
if(this.isEmpty()) {error("pop on empty list",this);return null;}
if(this.isEmpty()) {errorMessage("pop on empty list",this);return null;}
var h = this.head();
this.load(this.tail())
return h;
......@@ -128,7 +128,7 @@ List.prototype.load({
},
contains: function(object) {if(this.isEmpty()) {return false} else {return object===this.head() ? true : this.tail().contains(object)}},
insert: function(element,i) {
if(i>this.size()) {error("insert out of bounds, "+i+" : "+this.size(),this);return}//particular case
if(i>this.size()) {errorMessage("insert out of bounds, "+i+" : "+this.size(),this);return}//particular case
if(i==0) {//init
this.add(element);
} else {//recursion
......@@ -137,7 +137,7 @@ List.prototype.load({
}
},
replace: function(oldElement,newElement) {
if(this.isEmpty()) {error("<<element not found>> when trying to replace",this);return}//init-false
if(this.isEmpty()) {errorMessage("<<element not found>> when trying to replace",this);return}//init-false
if(oldElement===this.head()) {
this.set(0,newElement);//init-true
} else {
......@@ -155,34 +155,6 @@ List.prototype.load({
}
});
error: function(message,object) {
errorObject = object;
console.log(message);
}
/**
* returns the current date
*/
currentTime = function() {return (new Date()).toUTCString();}
// save
saveXHR = function(address) {
$.ajax({
url: address,
type: "PUT",
headers: {
Authorization: "Basic "+btoa("smik:asdf")},
fields: {
withCredentials: "true"
},
data: JSON.stringify(getCurrentDocument()),
success: function(){alert("saved");},
error: function(xhr) { alert("error while saving");}
});
};
/**
* load a public file with a basic ajax request
* @param address : the address of the document
......@@ -199,55 +171,6 @@ loadFile = function(address, type, instruction) {
});
}
// save
saveFile = function(address, content, instruction) {
$.ajax({
url: address,
type: "PUT",
dataType: "json",
data: JSON.stringify(content),
headers: { Authorization: "Basic "+btoa("smik:asdf")},
fields: { withCredentials: "true" },
success: instruction,
error: function(type) {
if(type.status==201 || type.status==204) {instruction();}//ajax thinks that 201 is an error...
}
});
}
deleteFile = function(address, instruction) {
$.ajax({
url: address,
type: "DELETE",
headers: { Authorization: "Basic "+btoa("smik:asdf")},
fields: { withCredentials: "true" },
success: instruction,
error: function(type) {
alert(type.status);//ajax thinks that 201 is an error...
}
});
}
// load
loadXHR = function(address) {
$.ajax({
url: address,
type: "GET",
dataType: "json",
cache:false,
headers: {
Authorization: "Basic "+btoa("smik:asdf")},
fields: {
withCredentials: "true"
},
success: function(data){
var cDoc = getCurrentDocument();
cDoc.load(data);
cDoc.setAsCurrentDocument();
}
});
}
/*
* wait an event before execute an action
* @param required : function we are waiting for a result
......@@ -273,7 +196,7 @@ tryUntilSucceed = function(func) {
var nb = 2;//avoid to test too much times
var execute = function() {
try {func.call();}
catch(e) {if(nb<100) {setTimeout(execute,nb*200);} console.log(e);}
catch(e) {if(nb<100) {setTimeout(execute,nb*200);}console.log(e);}
nb*=nb;
}
execute();
......@@ -287,4 +210,43 @@ var resize = function() {
$("div.main-right").width($(window).width()-$("div.main-left").width());
}
/**
* Used to debug
*/
errorMessage = function(message,object) {
errorObject = object;
console.log(message);
}
/**
* returns the current date
*/
currentTime = function() {return (new Date()).toUTCString();}
/**
* Paste a toolkit at the mouse position
*/
Tooltip = function() {
this.visible=false; // La variable i nous dit si la bulle est visible ou non
}
Tooltip.prototype = {
isVisible: function() {return this.visible;},
move: function(e) {$("div.toolLocation").css("left",e.pageX+5+"px").css("top",e.pageY + 10+"px");},
show: function(text) {
if(!this.isVisible()) {
$("div.toolLocation")
.css("display","inline")
.css("visibility","visible")
.html(text);
this.visible = true;
}
},
hide: function() {
if(this.isVisible()) {
$("div.toolLocation")
.css("display","none")
.css("visibility","hidden");
this.visible = false;
}
}
}
......@@ -10,8 +10,6 @@ setCurrentDocumentID = function(ID) {return localStorage.setItem("currentDocumen
/**
* class DocumentList
* This class provides methods to manipulate the list of documents of the current user
* As the list is stored in the localStorage, we are obliged to call "setDocumentList" after
* any content modification
* @param arg : a documentList json object to load
*/
var DocumentList = function(arg) {
......@@ -19,44 +17,45 @@ var DocumentList = function(arg) {
if(arg) {
this.load(arg);
this.load(new List(arg,JSONDocument));
this.selectionList = new List(arg.selectionList,JSONDocument);//load methods of selectionList
this.selectionList = new List(arg.selectionList);//load methods of selectionList
}
else {
this.displayedPage = 1;
List.call(this);
this.displayInformation = {};
this.displayInformation.page = 1;
this.selectionList = new List();
}
}
DocumentList.prototype = new List();
DocumentList.prototype.load({
addDocument: function(doc) {
this.add(doc);
setDocumentList(this);
this.display();
},
removeDocument: function(doc) {
var i = this.find(doc);
this.get(i).remove()//delete the file
this.remove(i);//remove from the list
setDocumentList(this);
this.display();
getCurrentStorage().save();//save changes
},
getSelectionList: function() { return this.selectionList; },
getSelectionList: function() {return this.selectionList;},
resetSelectionList: function() {
this.selectionList = new List();
for(var i=0; i<this.size(); i++) {
//display consequences
for(var i=this.getDisplayInformation().first-1; i<this.getDisplayInformation().last; i++) {
$("tr td.listbox-table-select-cell input#"+i).attr("checked",false);//uncheck
}
setDocumentList(this);
$("span#selected_row_number a").html(0);//display the selected row number
},
checkAll: function() {
this.selectionList = new List();
for(var i=0; i<this.size(); i++) {
this.getSelectionList().add(this.get(i));
$("tr td.listbox-table-select-cell input#"+i).attr("checked",true);
}
setDocumentList(this);
//display consequences
for(i=this.getDisplayInformation().first-1; i<this.getDisplayInformation().last; i++) {
$("tr td.listbox-table-select-cell input#"+i).attr("checked",true);//check
}
$("span#selected_row_number a").html(this.size());//display the selected row number
},
......@@ -66,56 +65,97 @@ DocumentList.prototype.load({
var doc = selection.pop();
this.removeDocument(doc);
}
this.display();
},
getDisplayedPage: function() {return this.displayedPage;},
setDisplayedPage: function(index) {this.displayedPage = index;},
getDisplayInformation: function() {return this.displayInformation;},
getDisplayedPage: function() {return this.getDisplayInformation().page;},
setDisplayedPage: function(index) {
this.displayInformation.page = index;
this.display();
},
changePage: function(event) {
var newPage = this.getDisplayedPage();
switch(event.target.className.split(" ")[0]) {
case "listbox_set_page":newPage = event.target.value;break;
case "listbox_next_page":newPage++;break;
case "listbox_previous_page":newPage--;break;
case "listbox_last_page":newPage = this.getDisplayInformation().lastPage;break;
case "listbox_first_page":newPage = 1;break;
}
this.setDisplayedPage(newPage);
},
/* display the list of documents in the web page */
displayContent: function() {
$("table.listbox tbody").html("");//empty the previous displayed list
var n = this.size();
for(var i=0;i<n;i++) {
var ligne = new Line(this.get(i),i);
for(var i=this.getDisplayInformation().first-1;i<this.getDisplayInformation().last;i++) {
var doc = this.get(i);
var ligne = new Line(doc,i);
ligne.updateHTML();
ligne.display();
if(this.getSelectionList().contains(doc)) {ligne.setSelected(true);}//check the box if selected
}
},
displayListInformation: function() {
if(this.size()>0) {
$("div.listbox-number-of-records").css("display","inline");
var step = getCurrentUser().getDisplayPreferences();
var first = (this.getDisplayedPage()-1)*step + 1;
var last = (this.size()<first+step) ? this.size() : first+step-1;
$("span#page_start_number").html(first);
$("span#page_stop_number").html(last);
$("span#page_start_number").html(this.getDisplayInformation().first);
$("span#page_stop_number").html(this.getDisplayInformation().last);
$("span#total_row_number a").html(this.size());
$("span#selected_row_number a").html(this.getSelectionList().size());
}
else {$("div.listbox-number-of-records").css("display","none");}
},
displayNavigationElements: function() {
var lastPage = this.getDisplayInformation().lastPage;
var disp = function(element,bool) {
bool ? $(element).css("display","inline") : $(element).css("display","none");
}
disp("div.listbox-navigation",this.getDisplayInformation().lastPage>1);
if(lastPage>1) {
$("div.listbox-navigation input.listbox_set_page").attr("value",this.getDisplayedPage());
$("div.listbox-navigation span.listbox_last_page").html(lastPage);
disp("div.listbox-navigation button.listbox_first_page",this.getDisplayedPage()>1);
disp("div.listbox-navigation button.listbox_previous_page",this.getDisplayedPage()>1);
disp("div.listbox-navigation button.listbox_next_page",this.getDisplayedPage()<lastPage);
disp("div.listbox-navigation button.listbox_last_page",this.getDisplayedPage()<lastPage);
}
},
display: function() {
this.updateDisplayInformation();
this.displayContent();
this.displayListInformation();
this.displayNavigationElements();
},
/* update the ith document information */
update: function(i) {
updateDocumentInformation: function(i) {
var list = this;
var doc = list.get(i);
loadFile(getDocumentAddress(doc),"json",function(data) {
getCurrentStorage().getDocument(getDocumentAddress(doc), function(data) {
doc.load(data);//todo : replace by data.header
doc.setContent("");//
list.set(i,doc);
setDocumentList(list);
});
},
/* update the document to be displayed */
updateDisplayInformation: function() {
var infos = this.getDisplayInformation();
infos.step = getCurrentUser().getSetting("displayPreferences"),//documents per page
infos.first = (infos.page-1)*infos.step + 1,//number of the first displayed document
infos.last = (this.size()<(infos.first+infos.step)) ? this.size() : infos.first+infos.step-1//number of the last displayed document
infos.lastPage = Math.ceil(this.size()/infos.step);
},
setAsCurrentDocumentList: function() {
this.display();
}
});
getDocumentList = function() {
return new DocumentList(JSON.parse(localStorage.getItem("documentList")));
}
setDocumentList = function(list) {
localStorage.setItem("documentList",JSON.stringify(list));
return getCurrentUser().getDocumentList();
}
......@@ -135,21 +175,18 @@ Line.prototype = {
getType: function() {return this.document.getType() ? this.document.getType() : "other";},
getHTML: function() {return this.html;},
setHTML: function(newHTML) {this.html = newHTML;},
setSelected: function(bool) {$("tr td.listbox-table-select-cell input#"+this.getID()).attr("checked",bool)},
isSelected: function() {
return $("tr td.listbox-table-select-cell input#"+this.getID()).attr("checked");
},
/* add the document of this line to the list of selected documents */
addToSelection: function() {
var list = getDocumentList();
list.getSelectionList().add(this.getDocument());
setDocumentList(list);
getDocumentList().getSelectionList().add(this.getDocument());
},
/* remove the document of this line from the list of selected documents */
removeFromSelection: function() {
var list = getDocumentList();
list.getSelectionList().removeElement(this.getDocument());
setDocumentList(list);
getDocumentList().getSelectionList().removeElement(this.getDocument());
},
/* check or uncheck the line */
changeState: function() {
......@@ -176,7 +213,7 @@ Line.prototype = {
.end()
.end()
.find("a.listbox-document-title").html(this.getDocument().getTitle()).end()
.find("a.listbox-document-state").html(this.getDocument().getState()[getCurrentUser().getLanguage()]).end()
.find("a.listbox-document-state").html(this.getDocument().getState()[getCurrentUser().getSetting("language")]).end()
.find("a.listbox-document-date").html(this.getDocument().getLastModification()).end()
.end());
},
......@@ -192,6 +229,9 @@ Line.loadHTML = function() {
Line.getOriginalHTML = function() {return Line.originalHTML;}
/**
* create a new document and start an editor to edit it
* @param type : the type of the document to create
......@@ -201,7 +241,8 @@ var createNewDocument = function(type) {
newDocument.setType(type);
newDocument.save(function() {
getDocumentList().addDocument(newDocument);
getDocumentList().add(newDocument);
getCurrentStorage().save();
startDocumentEdition(newDocument);
});
}
......@@ -30,26 +30,24 @@
href="images/ung/favicon.ico" />
<script type="text/javascript">
var initUser = function() {
var user = getCurrentUser();
user.setAsCurrentUser();
}
var init = function() {
//delete localStorage.documentList;//delete the list for tests
setCurrentPage(new Page());//provide methods on the page
initUser();//initialize the user
setCurrentPage(new Page("ung"));//provide methods on the page
getCurrentStorage().getUser().setAsCurrentUser();//initialize the user
if(getCurrentDocumentID()&&getDocumentList().get(getCurrentDocumentID())) {
/* update the list with the modifications of the last edited document
* (this method has to been rewritten if using multi users) */
getDocumentList().update(getCurrentDocumentID());
getDocumentList().updateDocumentInformation(getCurrentDocumentID());
delete localStorage.currentDocumentID;
}
waitBeforeSucceed(//display the list of documents
function(){return Line.loadHTML()},function() {
getDocumentList().resetSelectionList();
getDocumentList().display();}
getDocumentList().updateDisplayInformation();
getDocumentList().display();
resize();}
);
resize();
......@@ -124,9 +122,9 @@
<a id="right_message">Not Implemented yet</a>
<div id="preference_dialog" title="UNG Preferences"></div>
<a id="userName">Unknown</a>
| <a id="settings" href="#">Settings</a>
| <a id="help" href="#">Help</a>
| <a href="..WebSite_logout">Sign out</a>
| <a id="settings" href="">Settings</a>
| <a id="help" href="">Help</a>
| <a id="sign_out" href="" onclick="signOut()">Sign out</a>
</div></div>
......@@ -174,8 +172,7 @@
<div class="main">
<!-- Each aggregate of groups is a div wrapper --
<table class="wrapper" id="wrapper_main"><tr>-->
<!-- Each aggregate of groups is a div wrapper -->
<div class="wrapper" id="wrapper_main">
<!--<td class=" main-left">-->
<div class=" main-left">
......@@ -465,73 +462,87 @@
onclick="getDocumentList().deleteSelectedDocuments()">Delete
</button>
<button name="#" class="change_state">Change State</button>
</div>
</div></div>
</div>
<div class="listbox-navigation">
<button class="listbox_first_page your_listbox_first_page" onclick="getDocumentList().changePage(event)">
<span class="image"> </span>
</button>
<button class="listbox_previous_page your_listbox_previous_page" onclick="getDocumentList().changePage(event)">
<span class="image"> </span>
</button>
<input class="listbox_set_page your_listbox_set_page" value="1" size="1" onkeypress="if(event.keyCode==13){getDocumentList().changePage(event)}" />
/<span class="listbox_last_page">1</span>
<button class="listbox_next_page your_listbox_next_page" onclick="getDocumentList().changePage(event)">
<span class="image"> </span>
</button>
<button class="listbox_last_page your_listbox_last_page" onclick="getDocumentList().changePage(event)">
<span class="image"> </span>
</button>
</div>
<div class="field" title="">
<div class="listbox-head">
<div class="listbox-head-spacer"></div>
<div class="listbox-head-content">
<label> Document List </label>
<!-- Listbox head (in left) -->
<div class="listbox-head-title">
<div class="input">
<!-- List tree mode choice -->
<!-- Listbox title -->
<div class="listbox-header-box">
<div class="listbox-title">
<a href="..." class="your_listbox_title">
<span>Document List</span></a>
</div>
</div>
</div>
<div class="listbox-container">
<!-- Listbox nagivation (in right) -->
<div class="listbox-head-navigation">
<div class="listbox-content listbox-content-fixed-width">
<div class="listbox-head">
<!--Show search result in web mode-->
<div class="listbox-header-box">
<div class="listbox-number-of-records">
<div class="listbox-head-spacer"></div>
<!-- listbox start - stop number -->
<span id="page_start_number" class="listbox-current-page-start-number">1</span> -
<span id="page_stop_number" class="listbox-current-page-stop-number">...</span>
<span>of</span>
<div class="listbox-head-content">
<!-- listbox total rows number -->
<span id="total_row_number" class="listbox-current-page-total-number your_listbox-current-page-total-number">
<a>?</a> records
</span>
<!-- Listbox head (in left) -->
<div class="listbox-head-title">
<!-- listbox selected rows number -->
<span id="selected_row_number" class="your_listbox-current-item-number">
- <a>0</a> items selected
</span>
<!-- List tree mode choice -->
<!-- Listbox title -->
<div class="listbox-header-box">
<div class="listbox-title">
<a href="..." class="your_listbox_title">
<span>Document List</span></a>
</div>
</div>
</div>
<!-- Number of rows in ERP5 mode -->
<!-- List style display mode -->
<!--Page navigation -->
</div>
</div>
</div>
</div>
<!-- Listbox nagivation (in right) -->
<div class="listbox-head-navigation">
</div>
<!--Show search result in web mode-->
<div class="listbox-header-box">
<div class="listbox-number-of-records">
</div></div>
<!-- listbox start - stop number -->
<span id="page_start_number" class="listbox-current-page-start-number">1</span> -
<span id="page_stop_number" class="listbox-current-page-stop-number">...</span>
<span>of</span>
</div>
<!-- listbox total rows number -->
<span id="total_row_number" class="listbox-current-page-total-number your_listbox-current-page-total-number">
<a>?</a> records
</span>
<div class="field" title="">
<!-- listbox selected rows number -->
<span id="selected_row_number" class="your_listbox-current-item-number">
- <a>0</a> items selected
</span>
<label> Document List </label>
</div>
</div>
<div class="input">
<!--Page navigation -->
</div>
</div>
<div class="listbox-container">
</div>
<div class="listbox-content listbox-content-fixed-width">
<div class="listbox-body">
......
<?xml version="1.0" encoding="UTF-8"?>
<root>
<title> Welcome </title>
<content>
<fieldset class="widget">
<p></p>
<h2>Welcome to UNG Web Office</h2>
<div id="main-content">
<table width="100%" cellspacing="0" cellpadding="0" border="0">
<tbody>
<tr>
<td valign="top">
<div id="advertisement">
<b>Sign in to edit documents, spreadsheets and drawing and share this document with other users</b>
<br/>
<img src="images/ung/ung-logo.png" alt=""/>
</div>
</td>
<td>
<table id="field_table" style="display: table; width: 78%;">
<tbody>
<tr>
<td align="center">
<table>
<tbody>
<tr>
<td align="center" colspan="2">
<font size="-1">Login in</font>
</td>
</tr>
<tr><td></td></tr>
<tr>
<td align="center">
<label for="name">Name</label>
</td>
<td align="center">
<input id="name" type="text" value="" name="name" />
</td>
</tr>
<tr>
<td align="center">
<label for="id_provider">ID provider</label>
</td>
<td>
<input id="id_provider" type="text" value="" name="id_provider" />
</td>
</tr>
<tr>
<td align="center" colspan="2">
<input class="submit" onclick="logUser()" type="submit" value="Login" name="logged_in:method" />
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td>
<br/>
</td>
<td>
<table id="create-new-user" style="width: 78%; display: none;">
<tbody>
<tr>
<td>
<form id="create-user" action="javascript:createNewUser()" method="post">
<table width="100%">
<tbody>
<tr>
<td align="center" colspan="2">
<b>Create an account</b>
</td>
</tr>
<tr>
<td id="form-message" align="center" colspan="2"></td>
</tr>
<tr>
<td>First Name</td>
<td>
<input type="text" name="firstname" />
</td>
</tr>
<tr>
<td>Last Name</td>
<td>
<input type="text" name="lastname" />
</td>
</tr>
<tr>
<td>Email</td>
<td>
<input type="text" name="email" />
</td>
</tr>
<tr>
<td>Login name</td>
<td>
<input type="text" name="login_name" />
</td>
</tr>
<tr>
<td>Password</td>
<td>
<input type="password" name="password" />
</td>
</tr>
<tr>
<td>Confirm Password</td>
<td>
<input type="password" name="confirm" />
</td>
</tr>
<tr>
<td align="center" colspan="2">
<input class="submit" type="submit" value="Create Account" name="logged_in:method" />
</td>
</tr>
<tr>
<td id="back-login" align="left" colspan="2">
<a onclick="displayNewAccountForm(false)">&lt;&lt;Back</a>
</td>
</tr>
</tbody>
</table>
</form>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr><td></td></tr>
<tr>
<td></td>
<td>
<table id="new-account-table" style="display: table; width: 78%;">
<tbody>
<tr>
<td>
<table width="100%">
<tbody>
<tr>
<td align="center" colspan="2">
<b>Don't have an UNG Account?</b>
</td>
</tr>
<tr>
<td id="new-account-form" align="center" colspan="2" onclick="displayNewAccountForm(true)">Create an account now</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</div>
<div class="footer">
<a href="http://www.freecloudalliance.org/">Free Cloud Alliance</a>
-
<a href="#">Help</a>
</div>
<p></p>
</fieldset>
</content>
<dependencies>
<scriptfile>js/login.js</scriptfile>
</dependencies>
</root>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment