39 Commits

Author SHA1 Message Date
2dae59e749 Fix iOS issue : unability to edit large posts 2018-05-07 18:15:49 +02:00
e54998128f Catch JSON exceptions 2018-05-05 12:12:33 +02:00
1e2637ab48 Fix typo 2018-05-05 11:29:52 +02:00
03d1e8a91a Display user public notes 2018-05-05 11:27:57 +02:00
f4df523b1c User can set public notes 2018-05-05 11:14:13 +02:00
66a67d1491 Updated home page 2018-05-05 10:55:36 +02:00
ae445af083 Fix too long user website URL issue 2018-05-05 10:25:17 +02:00
d6d6c2aa4c Added users tag support 2018-05-03 22:44:22 +02:00
1044e3ff64 Added text parser 2018-05-03 22:05:06 +02:00
0ee542a3ac Update settings to match new tag system 2018-05-03 21:58:36 +02:00
a52e074e5b Display user tag 2018-05-03 21:56:58 +02:00
ee468de97d Removed useless variable declaration 2018-05-02 17:45:06 +02:00
f50dca1864 Remove useless configuration 2018-05-02 17:44:20 +02:00
2f399d17c0 Updated builder 2018-05-02 17:32:42 +02:00
34e38a505a Add Jenkins file 2018-05-02 16:49:51 +02:00
998e500154 Added date to conversations 2018-05-02 16:16:18 +02:00
df26ed4d38 Send a request to the server to update account image visibility 2018-05-01 11:42:23 +02:00
14fc7daf15 Fix UI issue 2018-05-01 11:00:53 +02:00
2dc1bb0732 Send a request to the server to delete account image 2018-05-01 10:57:58 +02:00
4dfe69da37 Improved style of account image settings section 2018-05-01 09:36:58 +02:00
e533d1e2f8 Can send a request to the server to upload an image 2018-05-01 08:59:14 +02:00
612949a86a Callout messages do not have messages. 2018-05-01 08:48:30 +02:00
944df583a6 Moved build to builder 2018-04-29 21:34:57 +02:00
d67cd14640 Made build more smart 2018-04-29 21:34:37 +02:00
f6297b39fb Enabled JS file reduction 2018-04-29 21:25:00 +02:00
7887080073 Fix issue in functions definition 2018-04-29 21:21:01 +02:00
8bb4df9f40 Build system can build different configurations 2018-04-29 21:09:22 +02:00
8740c2128a Moved API connexion configuration 2018-04-29 21:04:30 +02:00
3221cf2732 Update build script 2018-04-29 21:00:24 +02:00
4f9946063d First version of the build system 2018-04-29 20:58:01 +02:00
67acbbab4e Updated Google Fonts structure 2018-04-29 20:49:41 +02:00
8367a76906 Get account image settings from the server 2018-04-29 15:13:51 +02:00
159108b08b Fix word break issue 2018-04-28 10:17:22 +02:00
a61e6905bc Made slimscroll more user friendly when scrolling up in conversations 2018-04-28 10:04:12 +02:00
1509ca3533 Can go up in a conversation 2018-04-27 19:05:06 +02:00
f5818cf142 Splited addMessage and the generation of message HTML element 2018-04-27 18:41:57 +02:00
210e8406ad Restructured addMessage function 2018-04-27 18:26:16 +02:00
370512a6b6 Ready to display older messages 2018-04-26 17:55:38 +02:00
7b71aeed08 Upgraded weblink rendering 2018-04-26 17:51:34 +02:00
42 changed files with 1555 additions and 180 deletions

3
.gitignore vendored
View File

@ -1,4 +1,5 @@
# ---> VisualStudioCode # ---> VisualStudioCode
.settings .settings
# Build directory
output/*

11
Jenkinsfile vendored Normal file
View File

@ -0,0 +1,11 @@
pipeline {
agent { docker { image "registry.docker.internal/pierre42100/docker-comunicwebappscratch" } }
stages {
stage("build") {
steps {
sh 'php --version'
sh './builder build offline'
}
}
}
}

View File

@ -2,41 +2,41 @@
font-family: 'Source Sans Pro'; font-family: 'Source Sans Pro';
font-style: normal; font-style: normal;
font-weight: 300; font-weight: 300;
src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url(toadOcfmlt9b38dHJxOBGNbE_oMaV8t2eFeISPpzbdE.woff) format('woff'); src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url(googleFonts/toadOcfmlt9b38dHJxOBGNbE_oMaV8t2eFeISPpzbdE.woff) format('woff');
} }
@font-face { @font-face {
font-family: 'Source Sans Pro'; font-family: 'Source Sans Pro';
font-style: normal; font-style: normal;
font-weight: 400; font-weight: 400;
src: local('Source Sans Pro'), local('SourceSansPro-Regular'), url(ODelI1aHBYDBqgeIAH2zlBM0YzuT7MdOe03otPbuUS0.woff) format('woff'); src: local('Source Sans Pro'), local('SourceSansPro-Regular'), url(googleFonts/ODelI1aHBYDBqgeIAH2zlBM0YzuT7MdOe03otPbuUS0.woff) format('woff');
} }
@font-face { @font-face {
font-family: 'Source Sans Pro'; font-family: 'Source Sans Pro';
font-style: normal; font-style: normal;
font-weight: 600; font-weight: 600;
src: local('Source Sans Pro Semibold'), local('SourceSansPro-Semibold'), url(toadOcfmlt9b38dHJxOBGJ6-ys_j0H4QL65VLqzI3wI.woff) format('woff'); src: local('Source Sans Pro Semibold'), local('SourceSansPro-Semibold'), url(googleFonts/toadOcfmlt9b38dHJxOBGJ6-ys_j0H4QL65VLqzI3wI.woff) format('woff');
} }
@font-face { @font-face {
font-family: 'Source Sans Pro'; font-family: 'Source Sans Pro';
font-style: normal; font-style: normal;
font-weight: 700; font-weight: 700;
src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url(toadOcfmlt9b38dHJxOBGFkQc6VGVFSmCnC_l7QZG60.woff) format('woff'); src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url(googleFonts/toadOcfmlt9b38dHJxOBGFkQc6VGVFSmCnC_l7QZG60.woff) format('woff');
} }
@font-face { @font-face {
font-family: 'Source Sans Pro'; font-family: 'Source Sans Pro';
font-style: italic; font-style: italic;
font-weight: 300; font-weight: 300;
src: local('Source Sans Pro Light Italic'), local('SourceSansPro-LightIt'), url(fpTVHK8qsXbIeTHTrnQH6GGomRtBD2u8FwSY4jjlmeA.woff) format('woff'); src: local('Source Sans Pro Light Italic'), local('SourceSansPro-LightIt'), url(googleFonts/fpTVHK8qsXbIeTHTrnQH6GGomRtBD2u8FwSY4jjlmeA.woff) format('woff');
} }
@font-face { @font-face {
font-family: 'Source Sans Pro'; font-family: 'Source Sans Pro';
font-style: italic; font-style: italic;
font-weight: 400; font-weight: 400;
src: local('Source Sans Pro Italic'), local('SourceSansPro-It'), url(M2Jd71oPJhLKp0zdtTvoMzNrcjQuD0pTu1za2FULaMs.woff) format('woff'); src: local('Source Sans Pro Italic'), local('SourceSansPro-It'), url(googleFonts/M2Jd71oPJhLKp0zdtTvoMzNrcjQuD0pTu1za2FULaMs.woff) format('woff');
} }
@font-face { @font-face {
font-family: 'Source Sans Pro'; font-family: 'Source Sans Pro';
font-style: italic; font-style: italic;
font-weight: 600; font-weight: 600;
src: local('Source Sans Pro Semibold Italic'), local('SourceSansPro-SemiboldIt'), url(fpTVHK8qsXbIeTHTrnQH6PULlOK_XQENnt2ryrY843E.woff) format('woff'); src: local('Source Sans Pro Semibold Italic'), local('SourceSansPro-SemiboldIt'), url(googleFonts/fpTVHK8qsXbIeTHTrnQH6PULlOK_XQENnt2ryrY843E.woff) format('woff');
} }

View File

@ -10,3 +10,17 @@
a { a {
cursor: pointer; cursor: pointer;
} }
/**
* <a> like elements
*/
.a {
cursor: pointer;
outline: none;
text-decoration: none;
color: #3c8dbc;
}
.a:focus, .a:hover {
color: #72afd2;
}

View File

@ -80,15 +80,39 @@
/** /**
* Conversations messages * Conversations messages
*/ */
#conversationsElem .date-conversation-message {
margin-top: 2px;
text-align: center;
font-size: 70%;
font-style: italic;
}
#conversationsElem .conversation-msg-image { #conversationsElem .conversation-msg-image {
height: 50px; height: 50px;
} }
#conversationsElem .direct-chat-text {
word-break: break-all;
}
#conversationsElem .direct-chat-text .emoji { #conversationsElem .direct-chat-text .emoji {
height: 1em; height: 1em;
} }
#conversationsElem .direct-chat-text a, #conversationsElem .direct-chat-text .a {
color: inherit;
}
#conversationsElem .direct-chat-text.not-first-message::before, #conversationsElem .direct-chat-text.not-first-message::before,
#conversationsElem .direct-chat-text.not-first-message::after { #conversationsElem .direct-chat-text.not-first-message::after {
display: none; display: none;
} }
#conversationsElem .direct-chat-msg.not-last-message-from-user {
margin-bottom: 0px;
}
#conversationsElem .direct-chat-msg.not-last-message-from-user .direct-chat-img {
margin-bottom: -5px;
}

View File

@ -0,0 +1,21 @@
/**
* Account image settings section stylesheet
*
* @author Pierre HUBERT
*/
.box-account-image-settings .box-body {
text-align: center;
}
.box-account-image-settings .settings-account-image-preview {
max-width: 100%;
display: block;
margin: auto;
margin-top: 10px;
margin-bottom: 10px;
}
.box-account-image-settings .account-image-visibility-form {
text-align: justify;
}

View File

@ -0,0 +1,20 @@
/**
* Profile information stylesheet
*
* @author Pierre HUBERT
*/
.user-tag-in-profile {
color: #6f737b;
text-align: center;
font-size: 90%;
margin-bottom: 10px;
}
.about-user-box {
word-break: break-all;
}
.about-user-box .emoji {
height: 1em !important;
}

BIN
assets/img/pages/home/landingPage/img_background.jpg Executable file → Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 431 KiB

After

Width:  |  Height:  |  Size: 394 KiB

View File

@ -137,10 +137,31 @@ ComunicWeb.common.api = {
}, },
}; };
} }
else else {
//Prepare result
//Catch JSON parsing errors
try {
//Parse result
var result = JSON.parse(apiXHR.responseText); var result = JSON.parse(apiXHR.responseText);
} catch (error) {
//Report error
ComunicWeb.common.error.syntaxtError(error, apiXHR.responseText);
//Set arbitray result content
result = {
error : {
code: 1,
message: "Invalid response",
},
};
}
}
//We check if we got any error //We check if we got any error
if(result.error){ if(result.error){
//Log error //Log error

View File

@ -14,7 +14,7 @@
*/ */
ComunicWeb.common.error.submitError = function(errorLevel, errorMessage, errorCode, errorData){ ComunicWeb.common.error.submitError = function(errorLevel, errorMessage, errorCode, errorData){
//Prepare API request //Prepare API request
var apiURI = "webApp/reportError"; /*var apiURI = "webApp/reportError";
var params = { var params = {
"errorLevel": errorLevel, "errorLevel": errorLevel,
"errorMessage": errorMessage, "errorMessage": errorMessage,
@ -27,7 +27,7 @@ ComunicWeb.common.error.submitError = function(errorLevel, errorMessage, errorCo
nextAction = function(){}; nextAction = function(){};
//Send API request //Send API request
ComunicWeb.common.api.makeAPIrequest(apiURI, params, requireLoginToken, nextAction); ComunicWeb.common.api.makeAPIrequest(apiURI, params, requireLoginToken, nextAction);*/
} }
/** /**
@ -99,3 +99,74 @@ ComunicWeb.common.error.pageNotFound = function(additionnalData, targetElement){
//Everything seems to be OK //Everything seems to be OK
return true; return true;
} }
/**
* Handles and display SyntaxtError
*
* @param {SyntaxError} error The error
* @param {string} additional Additionnal information to include with
* the report
*/
ComunicWeb.common.error.syntaxtError = function(error, additional){
//Create a modal dialog to report error
var dialog = ComunicWeb.common.messages.createDialogSkeleton({
type: "danger",
title: "An error occurred"
});
//Display modal
$(dialog.modal).modal("show");
//Create close modal function
var closeModal = function(){
$(dialog.modal).modal('hide');
emptyElem(dialog.modal);
dialog.modal.remove();
}
dialog.closeModal.onclick = closeModal;
dialog.cancelButton.onclick = closeModal;
//Create error container
var errorContainer = createElem2({
appendTo: dialog.modalBody,
type: "div"
});
//Message
createElem2({
appendTo: errorContainer,
type: "p",
innerHTML: "An error has just occured. There are the details of the error. If this error occurs several times, please inform us at contact@communiquons.org ."
});
//Locate error
createElem2({
appendTo: errorContainer,
type: "p",
innerHTML: "<b>File:</b> "+error.fileName+" <b>Line:</b> " + error.lineNumber+ " <b>Column:</b> " + error.columnNumber
});
//Error message
createElem2({
appendTo: errorContainer,
type: "p",
innerHTML: "<b>Message:</b> " + error.message,
});
//Stack trace
createElem2({
appendTo: errorContainer,
type: "pre",
innerHTML: error.stack
});
//Check for additional information
if(additional){
createElem2({
appendTo: errorContainer,
type: "pre",
innerHTML: "Additionnal information: \n " + additional
});
}
}

View File

@ -99,6 +99,16 @@ var ComunicWeb = {
*/ */
createCalloutElem: function(calloutTitle, calloutMessage, calloutType){}, createCalloutElem: function(calloutTitle, calloutMessage, calloutType){},
/**
* Create and return a callout element
*/
createLoadingCallout: function(target){},
/**
* Create dialog skeleton
*/
createDialogSkeleton: function(info){},
/** /**
* Create and display a confirmation dialog * Create and display a confirmation dialog
*/ */
@ -128,6 +138,11 @@ var ComunicWeb = {
* Handle a 404 not found error * Handle a 404 not found error
*/ */
pageNotFound: function(additionnalData, targetElement){}, pageNotFound: function(additionnalData, targetElement){},
/**
* Handles and display SyntaxtError
*/
syntaxtError: function(error, additional){},
}, },
/** /**
@ -868,6 +883,13 @@ var ComunicWeb = {
}, },
/**
* Comunic specific text parser
*/
textParser: {
//TODO : implement
},
/** /**
* Countdown timer * Countdown timer
*/ */
@ -1129,6 +1151,13 @@ var ComunicWeb = {
password: { password: {
//TODO : implement //TODO : implement
}, },
/**
* Account image section
*/
accountImage: {
//TODO : implement
},
}, },
}, },

View File

@ -24,9 +24,11 @@ ComunicWeb.common.messages.createCalloutElem = function(calloutTitle, calloutMes
calloutElem.className = "callout callout-" + calloutType; calloutElem.className = "callout callout-" + calloutType;
//Add title //Add title
if(calloutTitle != ""){
var calloutTitleElem = document.createElement("h4"); var calloutTitleElem = document.createElement("h4");
calloutTitleElem.innerHTML = calloutTitle; calloutTitleElem.innerHTML = calloutTitle;
calloutElem.appendChild(calloutTitleElem) calloutElem.appendChild(calloutTitleElem)
}
//Add callout body //Add callout body
var calloutBody = document.createElement("div"); var calloutBody = document.createElement("div");
@ -37,6 +39,111 @@ ComunicWeb.common.messages.createCalloutElem = function(calloutTitle, calloutMes
return calloutElem; return calloutElem;
} }
/**
* Create loading callout element
*
* @param {HTMLElement} target Optionnal, the target of the callout element
* @return {HTMLElement} Generated loading callout element
*/
ComunicWeb.common.messages.createLoadingCallout = function(target){
var elem = this.createCalloutElem("Loading", "Please wait while this page is loading...", "info");
if(target)
target.appendChild(elem);
return elem;
}
/**
* Create dialog skeleton
*
* @param {object} info Information about the callout to create
* @argument {string} type The type of modal
* @param {string} title The title of the modal
* @return {object} Information about the created dialog
*/
ComunicWeb.common.messages.createDialogSkeleton = function(info){
data = {};
//Get modal type
var modalType = info.type ? info.type : "default";
//Get modal title
var modalTitle = info.title ? info.title : "";
//Create a modal root
data.modal = createElem2({
type: "div",
class: "modal modal-" + modalType
});
var modalDialog = createElem2({
appendTo: data.modal,
type: "div",
class: "modal-dialog"
});
data.modalContent = createElem2({
appendTo: modalDialog,
type: "div",
class: "modal-content",
});
//Modal header
data.modalHeader = createElem2({
appendTo: data.modalContent,
type: "div",
class: "modal-header"
});
data.closeModal = createElem2({
appendTo: data.modalHeader,
type: "button",
class: "close",
});
createElem2({
appendTo: data.closeModal,
type: "span",
innerHTML: "x"
});
//Modal title
data.modalTitle = createElem2({
appendTo: data.modalHeader,
type: "h4",
class: "modal-title",
innerHTML: modalTitle
});
//Modal body
data.modalBody = createElem2({
appendTo: data.modalContent,
type: "div",
class: "modal-body",
});
//Modal footer
data.modalFooter = createElem2({
appendTo: data.modalContent,
type: "div",
class: "modal-footer"
});
data.cancelButton = createElem2({
appendTo: data.modalFooter,
type: "button",
class: "btn btn-default",
innerHTML: "Cancel"
});
return data;
}
/** /**
* Create a confirmation dialog * Create a confirmation dialog
* *

View File

@ -127,8 +127,6 @@ function byId(nodeName){
* @return {Boolean} True for a success * @return {Boolean} True for a success
*/ */
function emptyElem(container){ function emptyElem(container){
//Get children references
var children = container.children;
//Process each child //Process each child
while(container.children.length > 0){ while(container.children.length > 0){
@ -191,8 +189,9 @@ function checkMail(emailAddress){
* @param {Object} infos Informations about the formgroup element to create * @param {Object} infos Informations about the formgroup element to create
* * @info {HTMLElement} target The target of the field * * @info {HTMLElement} target The target of the field
* * @info {String} label The label of the field * * @info {String} label The label of the field
* * @info {string} name The name of the field
* * @info {String} placeholder The placeholder of the field * * @info {String} placeholder The placeholder of the field
* * @info {Boolean} checked Defines if the fields has to be checked or not (checkbox only) * * @info {Boolean} checked Defines if the fields has to be checked or not (checkbox/radio only)
* * @info {Boolean} multiple Defines if the fields can accept more than one response * * @info {Boolean} multiple Defines if the fields can accept more than one response
* * @info {String} type The type of the field * * @info {String} type The type of the field
* * @info {string} value The default value of the input * * @info {string} value The default value of the input
@ -245,6 +244,41 @@ function createFormGroup(infos){
radioClass: 'iradio_flat-blue' radioClass: 'iradio_flat-blue'
}); });
} }
//In case of radio input
else if(infos.type == "radio"){
//Create radio
var input = createElem("input", labelElem) ;
input.type = "radio";
input.disabled = disabled;
if(infos.name)
input.name = infos.name;
if(infos.value)
input.value = infos.value;
//Check if input has to be checked by default
if(infos.checked){
if(infos.checked === true){
input.checked = "true";
}
}
//Add label value
var labelValue = createElem("span", labelElem);
labelValue.innerHTML = " "+infos.label;
//Enable iCheck
$(input).iCheck({
checkboxClass: 'icheckbox_flat-blue',
radioClass: 'iradio_flat-blue'
});
}
//Select2
else if(infos.type == "select2"){ else if(infos.type == "select2"){
//In case of select2 element //In case of select2 element
//Check for label //Check for label
@ -337,7 +371,7 @@ function create_radio(target, name, label){
}); });
//Add label //Add label
var labelElem = createElem2({ createElem2({
appendTo: radioLabel, appendTo: radioLabel,
type: "span", type: "span",
innerHTML: " "+ label innerHTML: " "+ label

View File

@ -230,7 +230,7 @@ ComunicWeb.components.comments.ui = {
}); });
//Parse emojies //Parse emojies
ComunicWeb.components.emoji.parser.parse({ ComunicWeb.components.textParser.parse({
element: commentContent element: commentContent
}); });

View File

@ -695,12 +695,12 @@ ComunicWeb.components.conversations.chatWindows = {
* Add a message to a conversation window * Add a message to a conversation window
* *
* @param {Integer} conversationID The ID of the conversation to update * @param {Integer} conversationID The ID of the conversation to update
* @param {Object} messageInfos Informations about the message to add * @param {Object} messageInfo Information about the message to add
* @return {Boolean} True for a success * @return {Boolean} True for a success
*/ */
addMessage: function(conversationID, messageInfos){ addMessage: function(conversationID, messageInfo){
//First, check if the conversation informations can be found //First, check if the conversation information can be found
if(!this.__conversationsCache["conversation-"+conversationID]){ if(!this.__conversationsCache["conversation-"+conversationID]){
ComunicWeb.debug.logMessage("Conversation Chat Windows : Error ! Couldn't add a message to the conversation because the conversation was not found !"); ComunicWeb.debug.logMessage("Conversation Chat Windows : Error ! Couldn't add a message to the conversation because the conversation was not found !");
return false; return false;
@ -709,127 +709,20 @@ ComunicWeb.components.conversations.chatWindows = {
//Else extract conversation informations //Else extract conversation informations
var convInfos = this.__conversationsCache["conversation-"+conversationID]; var convInfos = this.__conversationsCache["conversation-"+conversationID];
//Check if it is the current user who sent the message
var userIsPoster = messageInfos.ID_user == userID();
//Check if this is the first message of the conversation or not //Check if this is the first message of the conversation or not
if(!convInfos.lastMessage){ if(!convInfos.messages){
//Initialize last message object convInfos.messages = [];
convInfos.lastMessage = {
userID: 0,
messageContainer: false,
}
} }
//Check if message poster is the same as the last message //Get message HTML element add append it
if(convInfos.lastMessage.userID == messageInfos.ID_user){ var uiMessageInfo = this._get_message_element(convInfos, messageInfo);
//Skip message container creation & user avatar rendering... convInfos.box.messagesArea.appendChild(uiMessageInfo.rootElem);
var messageContainer = convInfos.lastMessage.messageContainer;
var firstMessageFromUser = false;
}
else {
//Initialize user & message informations elements
var firstMessageFromUser = true;
//Create message element //Perform post-processing operations
var messageContainer = createElem2({ var num = convInfos.messages.push(uiMessageInfo);
appendTo: convInfos.box.messagesArea,
type: "div",
class: "direct-chat-msg " + (userIsPoster ? "right" : "")
});
//Display message header //Check if it is not the first message from the current user
var messageHeader = createElem2({ this._makeMessageFollowAnotherMessage(convInfos, num - 1);
appendTo: messageContainer,
type: "div",
class: "direct-chat-info clearfix"
});
//Add user name
var usernameElem = createElem2({
appendTo: messageHeader,
type: "span",
class: "direct-chat-name pull-" + (userIsPoster ? "right" : "left"),
innerHTML: "Loading",
});
//Hide user name if it is the current user
if(userIsPoster)
usernameElem.style.display = "none";
//Add user account image
var userAccountImage = createElem2({
appendTo: messageContainer,
type: "img",
class: "direct-chat-img",
src: ComunicWeb.__config.assetsURL + "img/defaultAvatar.png",
alt: "User account image",
});
//Load user informations
if(convInfos.membersInfos["user-" + messageInfos.ID_user]){
//Get informations
var userInfos = convInfos.membersInfos["user-" + messageInfos.ID_user];
//Replace poster name
usernameElem.innerHTML = userInfos.firstName + " " + userInfos.lastName;
userAccountImage.src = userInfos.accountImage;
}
//Update conversation informations
convInfos.lastMessage = {
userID: messageInfos.ID_user,
messageContainer: messageContainer,
}
}
//Add message
var messageTargetElem = createElem2({
appendTo: messageContainer,
type: "div",
class: "direct-chat-text " + (!firstMessageFromUser ? "not-first-message" : ""),
});
//Add text message
var textMessage = createElem2({
appendTo: messageTargetElem,
type: "span",
innerHTML: removeHtmlTags(messageInfos.message), //Remove HTML tags
});
//Check if an image has to be added
if(messageInfos.image_path != null){
//Image link
var imageLink = createElem2({
appendTo: messageTargetElem,
type:"a",
href: messageInfos.image_path,
});
//Image element
createElem2({
appendTo: imageLink,
type: "img",
src: messageInfos.image_path,
class: "conversation-msg-image"
});
//Enable lightbox
imageLink.onclick = function(){
$(this).ekkoLightbox({
alwaysShowClose: true,
});
return false;
}
}
//Parse emojies in text message
ComunicWeb.components.emoji.parser.parse({
element: textMessage,
});
//Enable slimscroll //Enable slimscroll
$(convInfos.box.messagesArea).slimscroll({ $(convInfos.box.messagesArea).slimscroll({
@ -849,6 +742,217 @@ ComunicWeb.components.conversations.chatWindows = {
return true; return true;
}, },
/**
* Add old messages to a conversation window
*
* @param {number} conversationID The ID of the target conversation
* @param {array} messages The list of messages to add
*/
addOldMessages: function(conversationID, messages){
//First, check if the conversation information can be found
if(!this.__conversationsCache["conversation-"+conversationID]){
ComunicWeb.debug.logMessage("Conversation Chat Windows : Error ! Couldn't add a message to the conversation because the conversation was not found !");
return false;
}
//Else extract conversation informations
var conv = this.__conversationsCache["conversation-"+conversationID];
//Save the position of the oldest message element
var currOldestMessageElem = conv.messages[0].rootElem;
//Process the list of messages in reverse order
messages.reverse();
messages.forEach(function(message){
//Get message element
var uiMessageInfo = ComunicWeb.components.conversations.chatWindows._get_message_element(conv, message);
//Add the messages at the begining of the conversation
conv.box.messagesArea.insertBefore(uiMessageInfo.rootElem, conv.messages[0].rootElem);
//Add the message to the list
conv.messages.unshift(uiMessageInfo);
//Check if some information about the post can be updated
ComunicWeb.components.conversations.chatWindows._makeMessageFollowAnotherMessage(conv, 1);
});
//Update slimscroll
newScrollPos = currOldestMessageElem.offsetTop - 30;
if(newScrollPos < 0)
newScrollPos = 0;
$(conv.box.messagesArea).slimScroll({
scrollTo: newScrollPos + "px"
});
},
/**
* Generate message HTML node based on given information
*
* @param {object} conversationInfo Information about the created conversation
* @param {object} message Information about the target message
* @return {object} Information about the created message element
*/
_get_message_element: function(conversationInfo, message){
//Check if it is the current user who sent the message
var userIsPoster = message.ID_user == userID();
//Create message element
var messageContainer = createElem2({
type: "div",
class: "direct-chat-msg " + (userIsPoster ? "right" : "")
});
//Display message header
var messageHeader = createElem2({
appendTo: messageContainer,
type: "div",
class: "direct-chat-info clearfix"
});
//Add top information
var topInfosElem = createElem2({
appendTo: messageHeader,
type: "div",
class: "direct-chat-name pull-" + (userIsPoster ? "right" : "left"),
});
//Add user name
var usernameElem = createElem2({
appendTo: topInfosElem,
type: "span",
innerHTML: "Loading",
});
//Hide user name if it is the current user
if(userIsPoster)
usernameElem.style.display = "none";
//Add user account image
var userAccountImage = createElem2({
appendTo: messageContainer,
type: "img",
class: "direct-chat-img",
src: ComunicWeb.__config.assetsURL + "img/defaultAvatar.png",
alt: "User account image",
});
//Load user informations
if(conversationInfo.membersInfos["user-" + message.ID_user]){
//Get informations
var userInfos = conversationInfo.membersInfos["user-" + message.ID_user];
//Replace poster name
usernameElem.innerHTML = userInfos.firstName + " " + userInfos.lastName;
userAccountImage.src = userInfos.accountImage;
}
//Add message
var messageTargetElem = createElem2({
appendTo: messageContainer,
type: "div",
class: "direct-chat-text ",
});
//Add text message
var textMessage = createElem2({
appendTo: messageTargetElem,
type: "span",
innerHTML: removeHtmlTags(message.message), //Remove HTML tags
});
//Check if an image has to be added
if(message.image_path != null){
//Image link
var imageLink = createElem2({
appendTo: messageTargetElem,
type:"a",
href: message.image_path,
});
//Image element
createElem2({
appendTo: imageLink,
type: "img",
src: message.image_path,
class: "conversation-msg-image"
});
//Enable lightbox
imageLink.onclick = function(){
$(this).ekkoLightbox({
alwaysShowClose: true,
});
return false;
}
}
//Add date
var dateElem = createElem2({
appendTo: messageContainer,
type: "div",
class: "date-conversation-message",
innerHTML: ComunicWeb.common.date.timeDiffToStr(message.time_insert)
});
//Parse emojies in text message
ComunicWeb.components.textParser.parse({
element: textMessage,
});
//Return information about the message
return {
userID: message.ID_user,
rootElem: messageContainer,
userNameElem: usernameElem,
dateElem: dateElem,
time_insert: message.time_insert,
messageTargetElem: messageTargetElem,
accountImage: userAccountImage
};
},
/**
* Make a conversation message "follow" another conversation message from the
* same user
*
* @param {object} conv Information about the target conversation
* @param {number} num The number of the conversation message to update
*/
_makeMessageFollowAnotherMessage: function(conv, num){
if(conv.messages[num - 1]){
if(conv.messages[num-1].userID == conv.messages[num].userID){
//Update object class name
conv.messages[num].messageTargetElem.className += " not-first-message";
//Hide user name and account image
conv.messages[num].userNameElem.style.display = "none";
conv.messages[num].accountImage.style.display = "none";
//Update the class of the previous message
conv.messages[num-1].rootElem.className += " not-last-message-from-user";
}
//Check the difference of time between the two messages
if(conv.messages[num].time_insert - conv.messages[num - 1].time_insert < 3600
|| conv.messages[num].dateElem.innerHTML == conv.messages[num - 1].dateElem.innerHTML)
conv.messages[num].dateElem.style.display = "none";
}
},
/** /**
* Init top scroll detection (if required) * Init top scroll detection (if required)
* *
@ -887,7 +991,35 @@ ComunicWeb.components.conversations.chatWindows = {
scrollDetectionLocked = true; scrollDetectionLocked = true;
//Fetch older messages //Fetch older messages
console.log("Fetch old messages"); ComunicWeb.components.conversations.interface.getOlderMessages(
conversationID,
ComunicWeb.components.conversations.service.getOldestMessageID(conversationID),
10,
function(result){
//Unlock scroll detection
scrollDetectionLocked = false;
//Check for errors
if(result.error){
notify("An error occured while trying to fetch older messages for the conversation !");
return;
}
//Check for results
if(result.length == 0){
//Lock scroll detection in order to avoid useless traffic
scrollDetectionLocked = true;
return;
}
//Save the ID of the oldest message
ComunicWeb.components.conversations.service.setOldestMessageID(conversationID, result[0].ID);
//Display the list of messages
ComunicWeb.components.conversations.chatWindows.addOldMessages(conversationID, result);
}
);
}); });
} }
} }

View File

@ -322,6 +322,27 @@ ComunicWeb.components.conversations.interface = {
}, },
/**
* Get older message of a conversation
*
* @param {number} conversationID The ID of the conversation
* @param {number} oldestMessageID The ID of the oldest message known
* @param {number} limit The limit
* @param {function} callback
*/
getOlderMessages: function(conversationID, oldestMessageID, limit, callback){
//Perform a request on the API
var apiURI = "conversations/get_older_messages";
var params = {
conversationID: conversationID,
oldest_message_id: oldestMessageID,
limit: limit
};
ComunicWeb.common.api.makeAPIrequest(apiURI, params, true, callback);
},
/** /**
* Empty conversations cache * Empty conversations cache
* *

View File

@ -99,6 +99,12 @@ ComunicWeb.components.posts.edit = {
class: "editor-container" class: "editor-container"
}); });
//iOS fix : use slimscroll if required
updateDiv.style.maxHeight = (window.innerHeight - 200) + "px";
$(updateDiv).slimscroll({
height: "100%"
});
//Create update editor //Create update editor
var editorDiv = createElem2({ var editorDiv = createElem2({
appendTo: updateDiv, appendTo: updateDiv,

View File

@ -374,7 +374,7 @@ ComunicWeb.components.posts.ui = {
var link_img = createElem2({ var link_img = createElem2({
appendTo: linkContainer, appendTo: linkContainer,
type: "img", type: "img",
src: (infos.link_image != "default" ? infos.link_image : ComunicWeb.__config.assetsURL + "img/world.png"), src: (infos.link_image != null ? infos.link_image : ComunicWeb.__config.assetsURL + "img/world.png"),
class: "attachment-img", class: "attachment-img",
}); });
@ -383,7 +383,7 @@ ComunicWeb.components.posts.ui = {
appendTo: linkContainer, appendTo: linkContainer,
type: "h4", type: "h4",
class: "attachment-heading", class: "attachment-heading",
innerHTML: (infos.link_title != "default" ? infos.link_title : "Web page") innerHTML: (infos.link_title != null ? infos.link_title : "Web page")
}); });
@ -403,7 +403,7 @@ ComunicWeb.components.posts.ui = {
link_a_url.target = "_blank"; link_a_url.target = "_blank";
//Add description (if any) //Add description (if any)
if(infos.link_description != "default"){ if(infos.link_description != null){
var link_description = createElem2({ var link_description = createElem2({
appendTo: link_attachment_text, appendTo: link_attachment_text,
type: "p", type: "p",
@ -721,7 +721,7 @@ ComunicWeb.components.posts.ui = {
}); });
//Parse emojies //Parse emojies
ComunicWeb.components.emoji.parser.parse({ ComunicWeb.components.textParser.parse({
element: postContent element: postContent
}); });

View File

@ -85,4 +85,51 @@ ComunicWeb.components.settings.interface = {
}; };
ComunicWeb.common.api.makeAPIrequest(apiURI, params, true, callback); ComunicWeb.common.api.makeAPIrequest(apiURI, params, true, callback);
}, },
/**
* Get account image settings from the API
*
* @param {function} callback
*/
getAccountImage: function(callback){
var apiURI = "settings/get_account_image";
var params = {};
ComunicWeb.common.api.makeAPIrequest(apiURI, params, true, callback);
},
/**
* Upload a new account image
*
* @param {FormData} data The data containing information about the new account image
* @param {function} callback
*/
uploadAccountImage: function(data, callback){
var apiURI = "settings/upload_account_image";
ComunicWeb.common.api.makeFormDatarequest(apiURI, data, true, callback);
},
/**
* Delete current user account image
*
* @param {function} callback
*/
deleteAccountImage: function(callback){
var apiURI = "settings/delete_account_image";
var params = {};
ComunicWeb.common.api.makeAPIrequest(apiURI, params, true, callback);
},
/**
* Update the visibility of the account image
*
* @param {string} visibility The new visibility level for the account image
* @param {function} callback
*/
updateAccountImageVisibility: function(visibility, callback){
var apiURI = "settings/set_account_image_visibility";
var params = {
visibility: visibility
};
ComunicWeb.common.api.makeAPIrequest(apiURI, params, true, callback);
}
} }

View File

@ -0,0 +1,87 @@
/**
* Comunic specific text parser
*
* @author Pierre HUBERT
*/
ComunicWeb.components.textParser = {
/**
* Parse an element that contains some user input
*
* @param {object} info Information about the element to parse
*/
parse: function(info){
//Add space at the begining and the end of the content to ensure
//parsing will not encounter errors
info.element.innerHTML = " " + info.element.innerHTML + " ";
//Prepare users tag parsing
this._prepare_user_tag_parsing(info.element);
//Parse emojies
ComunicWeb.components.emoji.parser.parse({
element: info.element
});
//Parse users tags
this._parse_users_tag(info.element);
},
/**
* Prepare users tag parsing
*
* @param {HTMLElement} target The target element to prepare
*/
_prepare_user_tag_parsing: function(target){
//Find all occurences of users tag
while(target.innerHTML.match(/@[a-zA-Z0-9.]+/i)){
//Get user tag
var userTag = target.innerHTML.match(/@[a-zA-Z0-9.]+/i)[0];
var userID = userTag.replace("@", "");
target.innerHTML = target.innerHTML.replace(userTag, "<userTag>"+userID+"</userTag>");
}
},
/**
* Parse users tag
*
* @param {HTMLElement} target The target element where user tags has
* to be parsed
*/
_parse_users_tag: function(target){
//Get the list of user tags of the target
var nodes = target.getElementsByTagName("userTag");
for (const num in nodes) {
if (nodes.hasOwnProperty(num)) {
const node = nodes[num];
//Get target user ID
const userID = node.innerHTML;
//Adapt node content
node.innerHTML = "@" + userID;
node.className = "a";
//Set event listener
node.addEventListener("click", function(ev){
//Open user page
openUserPage(userID);
});
}
}
},
}

View File

@ -109,7 +109,7 @@ ComunicWeb.components.userSelect = {
* @param {array} usersID The ID of the users to push in select2 element * @param {array} usersID The ID of the users to push in select2 element
* @return {Boolean} True for a success * @return {Boolean} True for a success
*/ */
pushEntries(inputSelect, usersID){ pushEntries: function(inputSelect, usersID){
//Get informations about the entries //Get informations about the entries
getMultipleUsersInfos(usersID, function(usersInfos){ getMultipleUsersInfos(usersID, function(usersInfos){

View File

@ -17,16 +17,14 @@ ComunicWeb.pages.home.landingPage = {
document.title = "Comunic, a transparent social network"; document.title = "Comunic, a transparent social network";
//Prepare additional data //Prepare additional data
var additionalData = {}; var additionalData = {
//Preparing next actions //Background image URL
var afterParsingTemplate = function(){ backgroundImage: ComunicWeb.__config.assetsURL + "img/pages/home/landingPage/img_background.jpg"
//Change home background
byId("homeLandingScreen").style.backgroundImage = "url('"+ComunicWeb.__config.assetsURL + "img/pages/home/landingPage/img_background.jpg')";
}; };
//Apply template //Apply template
ComunicWeb.common.page.getAndShowTemplate(targetElement, additionalData, "pages/home/landingPage/home.tpl", afterParsingTemplate, true); ComunicWeb.common.page.getAndShowTemplate(targetElement, additionalData, "pages/home/landingPage/home.tpl", false, true);
} }
}; };

View File

@ -77,6 +77,20 @@ ComunicWeb.pages.settings.navigationPane = {
sectionSecurityLink.onclick = function(){ sectionSecurityLink.onclick = function(){
openPage("settings/security"); openPage("settings/security");
}; };
//Account image
var sectionSecurity = createElem2({
appendTo: elemList,
type: "li",
});
var sectionSecurityLink = createElem2({
appendTo: sectionSecurity,
type: "a",
innerHTML: "<i class='fa fa-file-image-o'></i> Account image"
});
sectionSecurityLink.onclick = function(){
openPage("settings/account_image");
};
} }
} }

View File

@ -0,0 +1,261 @@
/**
* Account image settings section
*
* @author Pierre HUBERT
*/
ComunicWeb.pages.settings.sections.accountImage = {
/**
* Open settings section
*
* @param {object} args Additionnal arguments
* @param {HTMLElement} target The target for the page
*/
open: function(args, target){
//Create a box
var box = createElem2({
appendTo: target,
type: "div",
class: "box box-primary box-account-image-settings"
});
//Add box header
var boxHead = createElem2({
appendTo: box,
type: "div",
class: "box-header",
});
var boxTitle = createElem2({
appendTo: boxHead,
type: "h3",
class: "box-title",
innerHTML: "Account image"
});
//Create box body
var boxBody = createElem2({
appendTo: box,
type: "div",
class: "box-body"
});
//Add loading callout
var loadMsg = ComunicWeb.common.messages.createLoadingCallout(boxBody);
//Fetch information about account image on the API
ComunicWeb.components.settings.interface.getAccountImage(function(result){
//Remove loading message
loadMsg.remove();
//Check for errors
if(result.error){
notify("Could not get account image information !", "danger");
return;
}
//Display the form
ComunicWeb.pages.settings.sections.accountImage._show_form(boxBody, result);
});
},
/**
* Display account images form
*
* @param {HTMLElement} target The target for the form
* @param {object} info Information about the form
*/
_show_form: function(target, info){
//Apply account image settings
var accountImageForm = createElem2({
type: "div",
appendTo: target
});
//First, offer the user to upload a new account image
var newAccountImageLabel = createElem2({
appendTo: accountImageForm,
type: "label"
});
var fileInput = createElem2({
appendTo: newAccountImageLabel,
type: "input",
elemType: "file"
});
fileInput.style.display = "none";
var chooseButton = createElem2({
appendTo: newAccountImageLabel,
type: "div",
class: "btn btn-primary",
innerHTML: "Upload a new account image"
});
//Add event listener
fileInput.addEventListener("change", function(e){
//Check if no file have been selected
if(fileInput.files.length == 0)
return;
//Upload the new file
//Display a callout message
var message = ComunicWeb.common.messages.createCalloutElem("", "Please wait while your picture is being uploaded...");
target.insertBefore(message, accountImageForm);
//Upload the image
var fd = new FormData();
fd.append("picture", fileInput.files[0], fileInput.files[0].name);
ComunicWeb.components.settings.interface.uploadAccountImage(fd, function(result){
//Remove message
message.remove();
//Check for errors
if(result.error){
notify("An error occured while trying to upload your image !", "danger");
return;
}
notify("Your picture has been successfully uploaded !", "success");
//Reload current page
ComunicWeb.common.system.reset();
});
});
//Stop here if the user does not have any account image
if(!info.has_image)
return;
//Display user account image
createElem2({
appendTo: accountImageForm,
type: "img",
src: info.image_url,
class: "settings-account-image-preview"
});
//Create actions contener
var actionsContener = createElem2({
appendTo: accountImageForm,
type: "div"
});
//Delete account image
var deleteImage = createElem2({
appendTo: accountImageForm,
type: "div",
class: "btn btn-danger",
innerHTML: "Delete image"
});
//Make delete button lives
deleteImage.addEventListener("click", function(e){
ComunicWeb.common.messages.confirm("Do you really want to delete your account image ? The operation can not be reverted !", function(res){
if(!res)
return;
//Make a request on the server
ComunicWeb.components.settings.interface.deleteAccountImage(function(callback){
//Delay action to let the time to the page to restart
setTimeout(function(){
//Check for errors
if(callback.error){
notify("Could not delete your account image !", "danger");
}
else
notify("Your account image has been successfully deleted!", "success");
}, 500);
//Reset the page
ComunicWeb.common.system.reset();
});
});
});
//Add the form to update visibility level
add_space(accountImageForm);
add_space(accountImageForm);
var visibilityForm = createElem2({
appendTo: accountImageForm,
type: "form",
class: "account-image-visibility-form"
});
//Title
createElem2({
appendTo: visibilityForm,
type: "h4",
innerHTML: "Account image visibility"
});
//Add the options
//Open
createFormGroup({
target: visibilityForm,
label: "Everyone",
name: "account-image-visibility",
type: "radio",
value: "open",
checked: info.visibility == "open"
});
//Public
createFormGroup({
target: visibilityForm,
label: "All Comunic users",
name: "account-image-visibility",
type: "radio",
value: "public",
checked: info.visibility == "public"
});
//Friends
createFormGroup({
target: visibilityForm,
label: "My friends only",
name: "account-image-visibility",
type: "radio",
value: "friends",
checked: info.visibility == "friends"
});
//Add update button
var updateButton = createElem2({
appendTo: visibilityForm,
type: "div",
class: "btn btn-primary",
innerHTML: "Update visibility"
});
updateButton.addEventListener("click", function(e){
//Get the new visibility level
var newVisibility = visibilityForm.elements["account-image-visibility"].value;
//Make a request over the server
ComunicWeb.components.settings.interface.updateAccountImageVisibility(newVisibility, function(callback){
//Check for errors
if(callback.error){
notify("Could update the visibility of your account image!", "danger");
}
else
notify("The visibility of your account image have been successfully updated!", "success");
});
});
}
}

View File

@ -42,7 +42,7 @@ ComunicWeb.pages.settings.sections.general = {
}); });
//Display loading message //Display loading message
var loadingMsg = ComunicWeb.common.messages.createCalloutElem("Loading", "Please wait while this page is loading...", "info"); var loadingMsg = ComunicWeb.common.messages.createLoadingCallout();
boxBody.appendChild(loadingMsg); boxBody.appendChild(loadingMsg);
//Load general settings information //Load general settings information
@ -194,10 +194,19 @@ ComunicWeb.pages.settings.sections.general = {
value: infos.personnal_website != "null" ? infos.personnal_website : "" value: infos.personnal_website != "null" ? infos.personnal_website : ""
}); });
//Public notes
var publicNotes = createFormGroup({
target: target,
label: "Public notes for your account 255 characters max (optionnal)",
type: "textarea",
placeholder: "Notes about your account...",
value: infos.publicNote != "null" ? infos.publicNote : ""
});
//Virtual directory //Virtual directory
var virtualDirectory = createFormGroup({ var virtualDirectory = createFormGroup({
target: target, target: target,
label: "Virtual directory for your user page (" + ComunicWeb.__config.siteURL + "user/{virtual_directory})", label: "Virtual directory for your user page (" + ComunicWeb.__config.siteURL + "user/{virtual_directory})<br />Account tag (in the form @{virtual_directory})",
type: "text", type: "text",
placeholder: "Eg. john.way", placeholder: "Eg. john.way",
value: infos.virtual_directory != "null" ? infos.virtual_directory : "" value: infos.virtual_directory != "null" ? infos.virtual_directory : ""
@ -264,7 +273,8 @@ ComunicWeb.pages.settings.sections.general = {
allowPostsFromFriends: allowPostsFromFriends.checked, allowPostsFromFriends: allowPostsFromFriends.checked,
publicFriendsList: publicFriendsList.checked, publicFriendsList: publicFriendsList.checked,
personnalWebsite: personnalWebsite.value, personnalWebsite: personnalWebsite.value,
virtualDirectory: virtualDirectory.value virtualDirectory: virtualDirectory.value,
publicNote: publicNotes.value,
}; };
//Lock send button //Lock send button

View File

@ -29,4 +29,12 @@ ComunicWeb.pages.settings.sectionsList = {
title: "Password", title: "Password",
handler: "ComunicWeb.pages.settings.sections.password.open", handler: "ComunicWeb.pages.settings.sections.password.open",
}, },
/**
* Account image
*/
account_image: {
title: "Account image",
handler: "ComunicWeb.pages.settings.sections.accountImage.open"
},
} }

View File

@ -87,7 +87,7 @@ ComunicWeb.pages.userPage.posts = {
* @param {HTMLElement} target The target for the posts * @param {HTMLElement} target The target for the posts
* @param {function} callback What to do once the posts have been loaded * @param {function} callback What to do once the posts have been loaded
*/ */
_load_posts(userInfos, target, callback){ _load_posts: function(userInfos, target, callback){
//Get the posts from the API //Get the posts from the API
ComunicWeb.components.posts.interface.get_user(userInfos.userID, this._last_post_id, function(result){ ComunicWeb.components.posts.interface.get_user(userInfos.userID, this._last_post_id, function(result){

View File

@ -64,6 +64,16 @@ ComunicWeb.pages.userPage.profileInfos = {
}); });
//Add user virtual directory (if any)
if(infos.virtualDirectory != ""){
var userTag = createElem2({
appendTo: boxBody,
type: "div",
innerHTML: "@"+ infos.virtualDirectory,
class: "user-tag-in-profile"
});
}
//Show user likes //Show user likes
var userLikesTarget = createElem2({ var userLikesTarget = createElem2({
@ -166,7 +176,7 @@ ComunicWeb.pages.userPage.profileInfos = {
var boxRoot = createElem2({ var boxRoot = createElem2({
appendTo: target, appendTo: target,
type: "div", type: "div",
class: "box box-primary" class: "box box-primary about-user-box"
}); });
//Add box header //Add box header
@ -227,6 +237,41 @@ ComunicWeb.pages.userPage.profileInfos = {
}); });
} }
//Add user public note (if any)
if(infos.publicNote){
var userNote = createElem2({
appendTo: boxBody,
type: "strong"
});
createElem2({
appendTo: userNote,
type: "i",
class: "fa fa-file-text-o margin-r-5"
});
createElem2({
appendTo: userNote,
type: "span",
innerHTML: "Note"
});
var publicNotes = createElem2({
appendTo: boxBody,
type: "p",
class: "text-muted",
innerHTML: infos.publicNote
});
//Parse text
ComunicWeb.components.textParser.parse({
element: publicNotes
});
//Add separator
createElem2({
appendTo: boxBody,
type: "hr",
});
}
//Add informations about membership //Add informations about membership
var membershipInfos = createElem2({ var membershipInfos = createElem2({
appendTo: boxBody, appendTo: boxBody,

View File

@ -38,7 +38,7 @@
<div class="message"> <div class="message">
<h1>Congratulations!</h1> <h1>Congratulations!</h1>
<br /> <br />
<h4>Your account has been successfully created! Login now to use all the features of Comunic !</h4> <h4>Your account has been successfully created! <br /> Login now to use all the features of Comunic!</h4>
<br /> <br />
<a target="login" class="btn btn-primary btn-lg">Login</a> <a target="login" class="btn btn-primary btn-lg">Login</a>
</div> </div>

View File

@ -13,7 +13,7 @@
<h3>Free social network that respect your privacy.</h3> <h3>Free social network that respect your privacy.</h3>
<br /> <br />
<a class="btn btn-lg btn-primary" target="create_account">Create account</a> <a class="btn btn-lg btn-primary" target="create_account">Sign up</a>
<a class="btn btn-lg btn-success" target="login">Sign in</a> <a class="btn btn-lg btn-success" target="login">Sign in</a>
</div> </div>
</div> </div>
@ -23,13 +23,15 @@
<!-- Page styles --> <!-- Page styles -->
<style type="text/css"> <style type="text/css">
#homeLandingScreen{ #homeLandingScreen{
background-image: url("{backgroundImage}");
background-position: 0% 50%;
width: 100%; width: 100%;
height: 100%; height: 100%;
position: fixed; position: fixed;
text-align: center; text-align: center;
padding: 10px; padding: 10px;
background-position: 50% 50%;
display: table; display: table;
top: 0; top: 0;
} }

286
builder Executable file
View File

@ -0,0 +1,286 @@
#!/usr/bin/env php
###########################
# ComunicWeb build script #
# #
# @author Pierre HUBERT #
###########################
<?php
//Output directory
define("OUTPUT_DIRECTORY", __DIR__."/output/");
//Temporary file
define("TEMP_FILE", __DIR__."/output/temp");
//Defines some utilities
/**
* Display a message on the screen
*
* @param string $message The message to display on the screen
* @param bool $new_section Specify whether the message refers to a
* new build section or not
*/
function notice(string $message, bool $new_section = false) {
echo ($new_section ? "\n\n" : "").$message,"\n";
}
/**
* Append a string at the begining of each entry of an array
*
* @param string $input The string to append to each array entry
* @param array $array The array to process
* @return array Updated array
*/
function array_put_begining(string $input, array $array){
foreach($array as $num => $val)
$array[$num] = $input.$val;
return $array;
}
/**
* Copy an array of file into a specific target file
*
* @param array $files The list of file to copy
* @param string $target The target file to create
* @param bool TRUE for a success / FALSE else
*/
function files_to_file(array $files, string $target) : bool {
$source = "";
foreach($files as $file){
$source .= file_get_contents($file)."\n";
}
return file_put_contents($target, $source) != FALSE;
}
/**
* Copy an array of files into a specific target file using uglifyJS
*
* @param array $files The name of the source file
* @param string $target The target file
* @return bool TRUE in case of success / FALSE in case of failure
*/
function js_files_to_file(array $files, string $target){
$source = "";
//Delete any previous temporary file
if(file_exists(TEMP_FILE))
unlink(TEMP_FILE);
foreach($files as $file){
//Compress file
notice("Parsing with UGLIFYJS: ".$file);
exec("/usr/bin/uglifyjs '".$file."' -c -o ".TEMP_FILE, $output, $exit_code);
//Get the content of the file
$source .= "\n".file_get_contents(TEMP_FILE);
if($exit_code != 0){
notice("An error (".$exit_code.") occured while parsing file ".$file, TRUE);
exit(10);
}
}
//Delete the temp file
unlink(TEMP_FILE);
return file_put_contents($target, $source) != FALSE;
}
/**
* Delete the entire content of directory
*
* @param string $path The path of the directory to delete
*/
function delDir(string $path){
if(is_dir($path) == TRUE){
$rootFolder = scandir($path);
if(sizeof($rootFolder) > 2){
foreach($rootFolder as $folder){
if($folder != "." && $folder != ".."){
//Pass the subfolder to function
delDir($path."/".$folder);
}
}
//On the end of foreach the directory will be cleaned, and you will can use rmdir, to remove it
rmdir($path);
}
}
else {
if(file_exists($path) == TRUE){
//Suppression du fichier
unlink($path);
}
}
}
// copies files and non-empty directories
function rcopy(string $src, string $dst) {
if (is_dir($src)) {
mkdir($dst, 0777, true);
$files = scandir($src);
foreach ($files as $file)
if ($file != "." && $file != "..") rcopy("$src/$file", "$dst/$file");
}
else if (file_exists($src)) copy($src, $dst);
}
//Initialize page
require_once __DIR__."/system/system.php";
/**
* Build application
*/
function build() {
if(!isset($_SERVER['argv'][2]))
exit(notice("Usage: ./build build [configuration]", TRUE));
//Defines some variables
$debug_conf = "dev";
$release_conf = $_SERVER['argv'][2];
//Load configurations
notice("Load configurations.", TRUE);
notice("Debug config: ".$debug_conf);
notice("Release config: ".$release_conf);
load_config($debug_conf);
$debug = new $debug_conf;
$path_debug_assets = __DIR__."/".$debug::PATH_ASSETS;
load_config($release_conf);
$release = new $release_conf;
$path_release_assets = OUTPUT_DIRECTORY.$release::PATH_ASSETS;
//Clean directory
notice("Clean build directory", TRUE);
if(file_exists(OUTPUT_DIRECTORY))
delDir(OUTPUT_DIRECTORY);
mkdir(OUTPUT_DIRECTORY, 0777, true);
mkdir($path_release_assets, 0777, true);
//Create unminified version
notice("Create unminified files versions", TRUE);
//3rd party CSS
notice("Third Party CSS");
$thirdPartyDebugFiles = array_put_begining($path_debug_assets, $debug::THIRD_PARTY_CSS);
$targetThirdPartyCSS = $path_release_assets.$release::THIRD_PARTY_CSS;
files_to_file($thirdPartyDebugFiles, $targetThirdPartyCSS);
//3rd party JS
notice("Third Party JS");
$thirdPartyDebugFiles = array_put_begining($path_debug_assets, $debug::THIRD_PARTY_JS);
$targetThirdPartyJS = $path_release_assets.$release::THIRD_PARTY_JS;
js_files_to_file($thirdPartyDebugFiles, $targetThirdPartyJS);
//App CSS
notice("App CSS");
$appDebugFiles = array_put_begining($path_debug_assets, $debug::APP_CSS);
$targetAppCSS = $path_release_assets.$release::APP_CSS;
files_to_file($appDebugFiles, $targetAppCSS);
//App JS
notice("App JS");
$appDebugFiles = array_put_begining($path_debug_assets, $debug::APP_JS);
$targetAppJS = $path_release_assets.$release::APP_JS;
js_files_to_file($appDebugFiles, $targetAppJS);
//Make some adpations on third party files
$source = file_get_contents($targetThirdPartyCSS);
$source = str_replace("../fonts/fontawesome", "fontawesome_fonts/fontawesome", $source);
file_put_contents($targetThirdPartyCSS, $source);
//Copy font awesome files and twemojies files + Google Fonts
rcopy($path_debug_assets."3rdparty/adminLTE/plugins/font-awesome/fonts", $path_release_assets."fontawesome_fonts");
rcopy($path_debug_assets."3rdparty/twemoji/2/72x72/", $path_release_assets."3rdparty/twemoji/2/72x72/");
rcopy($path_debug_assets."3rdparty/adminLTE/plugins/googleFonts/googleFonts/", $path_release_assets."googleFonts/");
rcopy($path_debug_assets."3rdparty/wdt-emoji/sheets/", $path_release_assets."3rdparty/wdt-emoji/sheets/");
//Copy images and templates
rcopy($path_debug_assets."img/", $path_release_assets."img/");
rcopy($path_debug_assets."templates/", $path_release_assets."templates/");
//Create main HTML file
notice("Generate PHP root file");
$page_src = '<?php
//We check if it is a redirection to handle 404 errors
if(isset($_SERVER["REDIRECT_URL"])){
//We check if it is an asset request
if(preg_match("<assets>", $_SERVER["REDIRECT_URL"])){
//This is a 404 not found error...
echo "<p>Error! 404 not found</p>";
http_response_code(404);
exit();
}
} ?>';
$page_src .= load_page($release_conf);
file_put_contents(OUTPUT_DIRECTORY."index.php", $page_src);
// Add .htaccess file
$htaccess = '<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.php [L]
</IfModule>
';
file_put_contents(OUTPUT_DIRECTORY.".htaccess", $htaccess);
//Done
notice("Done.", TRUE);
} //BUILD
/**
* Clean build directory
*/
function clean(){
notice("Cleaning build directory.", TRUE);
delDir(OUTPUT_DIRECTORY);
}
//Get the action and do it
if(!isset($_SERVER['argv'][1]))
exit("Usage: ./build [action]");
$action = $_SERVER['argv'][1];
switch($action){
case "build":
build();
break;
case "clean":
clean();
break;
default:
notice("Accepted commands are build, clean.", TRUE);
}

View File

@ -7,6 +7,13 @@
class Dev { class Dev {
/**
* API access and credentials
*/
const API_URL = "http://devweb.local/comunic/api/";
const API_SERVICE_NAME = "ComunicWeb";
const API_SERVICE_TOKEN = "12XU67pJUlnNQ";
/** /**
* Site URL * Site URL
*/ */
@ -18,7 +25,12 @@ class Dev {
const PROD_MODE = false; const PROD_MODE = false;
/** /**
* Path to assets * Path to assets (relative to the base project)
*/
const PATH_ASSETS = "assets/";
/**
* URL to assets
*/ */
const ASSETS_URL = "http://devweb.local/comunic/v2/assets/"; const ASSETS_URL = "http://devweb.local/comunic/v2/assets/";
@ -30,6 +42,7 @@ class Dev {
"3rdparty/adminLTE/bootstrap/css/bootstrap.min.css", "3rdparty/adminLTE/bootstrap/css/bootstrap.min.css",
"3rdparty/adminLTE/plugins/font-awesome/css/font-awesome.min.css", "3rdparty/adminLTE/plugins/font-awesome/css/font-awesome.min.css",
"3rdparty/adminLTE/plugins/ionicons/css/ionicons.min.css", "3rdparty/adminLTE/plugins/ionicons/css/ionicons.min.css",
"3rdparty/adminLTE/plugins/googleFonts/css.css",
//iCheck //iCheck
"3rdparty/adminLTE/plugins/iCheck/square/blue.css", "3rdparty/adminLTE/plugins/iCheck/square/blue.css",
@ -168,6 +181,7 @@ class Dev {
//User Page //User Page
"css/pages/userPage/main.css", "css/pages/userPage/main.css",
"css/pages/userPage/accessForbidden.css", "css/pages/userPage/accessForbidden.css",
"css/pages/userPage/profileInfos.css",
//Post page //Post page
"css/pages/postPage/main.css", "css/pages/postPage/main.css",
@ -177,6 +191,7 @@ class Dev {
"css/pages/settings/sections/general.css", "css/pages/settings/sections/general.css",
"css/pages/settings/sections/security.css", "css/pages/settings/sections/security.css",
"css/pages/settings/sections/password.css", "css/pages/settings/sections/password.css",
"css/pages/settings/sections/accountImage.css",
//Latest post page stylesheet //Latest post page stylesheet
"css/pages/latestPosts/main.css", "css/pages/latestPosts/main.css",
@ -298,6 +313,9 @@ class Dev {
//Modern textarea handler //Modern textarea handler
"js/components/textarea.js", "js/components/textarea.js",
//Comunic custom text parser
"js/components/textParser.js",
//Countdown timer //Countdown timer
"js/components/countdown.js", "js/components/countdown.js",
@ -345,6 +363,7 @@ class Dev {
"js/pages/settings/sections/general.js", "js/pages/settings/sections/general.js",
"js/pages/settings/sections/security.js", "js/pages/settings/sections/security.js",
"js/pages/settings/sections/password.js", "js/pages/settings/sections/password.js",
"js/pages/settings/sections/accountImage.js",
//Login page //Login page
"js/pages/login.js", "js/pages/login.js",

View File

@ -12,11 +12,4 @@ class Config {
*/ */
const VERSION = "0.1.1"; const VERSION = "0.1.1";
/**
* API access and credentials
*/
const API_URL = "http://devweb.local/comunic/api/";
const API_SERVICE_NAME = "ComunicWeb";
const API_SERVICE_TOKEN = "12XU67pJUlnNQ";
} }

View File

@ -0,0 +1,76 @@
<?php
/**
* PHP offline build config for the website
*
* @author Pierre HUBERT
*/
class Offline {
/**
* API access and credentials
*/
const API_URL = "http://devweb.local/comunic/api/";
const API_SERVICE_NAME = "ComunicWeb";
const API_SERVICE_TOKEN = "12XU67pJUlnNQ";
/**
* Site URL
*/
const SITE_URL = "http://devweb.local/comunic/v2/output/";
/**
* Site production mode
*/
const PROD_MODE = TRUE;
/**
* Path to assets (relative to the build folder)
*/
const PATH_ASSETS = "assets/";
/**
* Path to assets (URL)
*/
const ASSETS_URL = "http://devweb.local/comunic/v2/output/assets/";
/**
* Third party CSS files
*/
const THIRD_PARTY_CSS = "third_party_css.css";
/**
* Third party Javascript files
*/
const THIRD_PARTY_JS = "third_party.js";
/**
* Third party Javascript files (unminified)
*/
const THIRD_PARTY_UNMINIFIED_JS = "third_party.unminified.js";
/**
* Application CSS files
*/
const APP_CSS = "app.css";
/**
* Application JS files
*/
const APP_JS = "app.js";
/**
* Application JS files (unminifieds)
*/
const APP_UNMINIFIED_JS = "app.unminified.js";
/**
* Language settings
*/
const DEFAULT_LANGUAGE = "en";
/**
* Templates settings
*/
const TEMPLATES_PATH = "templates/";
}

View File

@ -19,7 +19,7 @@ require_once __DIR__."/config/global.config.php";
function load_page(string $config) : string { function load_page(string $config) : string {
//Load configuration //Load configuration
require __DIR__."/config/".$config.".config.php"; load_config($config);
$conf = new $config(); $conf = new $config();
//Load page template //Load page template
@ -32,14 +32,31 @@ function load_page(string $config) : string{
$source = str_replace("{js_config}", get_javascript_config($conf), $source); $source = str_replace("{js_config}", get_javascript_config($conf), $source);
//Update assets inclusion //Update assets inclusion
if(is_array($conf::THIRD_PARTY_CSS)){
$source = str_replace("{THIRD_PARTY_CSS}", src_inc_list_css($conf::ASSETS_URL, $conf::THIRD_PARTY_CSS), $source); $source = str_replace("{THIRD_PARTY_CSS}", src_inc_list_css($conf::ASSETS_URL, $conf::THIRD_PARTY_CSS), $source);
$source = str_replace("{APP_CSS}", src_inc_list_css($conf::ASSETS_URL, $conf::APP_CSS), $source); $source = str_replace("{APP_CSS}", src_inc_list_css($conf::ASSETS_URL, $conf::APP_CSS), $source);
$source = str_replace("{THIRD_PARTY_JS}", src_inc_list_js($conf::ASSETS_URL, $conf::THIRD_PARTY_JS), $source); $source = str_replace("{THIRD_PARTY_JS}", src_inc_list_js($conf::ASSETS_URL, $conf::THIRD_PARTY_JS), $source);
$source = str_replace("{APP_JS}", src_inc_list_js($conf::ASSETS_URL, $conf::APP_JS), $source); $source = str_replace("{APP_JS}", src_inc_list_js($conf::ASSETS_URL, $conf::APP_JS), $source);
}
else {
$source = str_replace("{THIRD_PARTY_CSS}", src_inc_css($conf::ASSETS_URL.$conf::THIRD_PARTY_CSS), $source);
$source = str_replace("{APP_CSS}", src_inc_css($conf::ASSETS_URL.$conf::APP_CSS), $source);
$source = str_replace("{THIRD_PARTY_JS}", src_inc_js($conf::ASSETS_URL.$conf::THIRD_PARTY_JS), $source);
$source = str_replace("{APP_JS}", src_inc_js($conf::ASSETS_URL.$conf::APP_JS), $source);
}
return $source; return $source;
} }
/**
* Load a configuration
*
* @param string $name The name of the configuration to load
*/
function load_config(string $config){
require_once __DIR__."/config/".$config.".config.php";
}
/** /**
* Get javascript configuration * Get javascript configuration
* *
@ -67,15 +84,15 @@ function get_javascript_config($config) : string {
siteURL: '".$config::SITE_URL."', siteURL: '".$config::SITE_URL."',
//API configuration //API configuration
apiURL: '".Config::API_URL."', apiURL: '".$config::API_URL."',
apiServiceName: '".Config::API_SERVICE_NAME."', apiServiceName: '".$config::API_SERVICE_NAME."',
apiServiceToken: '".Config::API_SERVICE_TOKEN."', apiServiceToken: '".$config::API_SERVICE_TOKEN."',
//Default language //Default language
defaultLanguage: '".$config::DEFAULT_LANGUAGE."', defaultLanguage: '".$config::DEFAULT_LANGUAGE."',
//LanguagesPath "/*LanguagesPath
languagesPath: '".$config::ASSETS_URL.$config::LANGUAGE_PATH."', "languagesPath: '".$config::ASSETS_URL.$config::LANGUAGE_PATH."', */."
}; };