1
0
Fork 0

restructuring for PR for friendica main repo

This commit is contained in:
rabuzarus 2016-05-25 15:12:29 +02:00
commit b67378ac69
298 changed files with 0 additions and 0 deletions

View file

@ -0,0 +1,202 @@
/**
* Filebrowser - Friendica Communications Server
*
* Copyright (c) 2010-2015 the Friendica Project
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code handle user interaction for image/file upload/browser dialog.
* Is loaded from filebrowser_plain.tpl
*
* To load filebrowser in colorbox, call
*
* Dialog.doImageBrowser(eventname, id);
*
* or
*
* Dialog.doFileBrowser(eventname, id);
*
* where:
*
* eventname: event name to catch return value
* id: id returned to event handler
*
* When user select an item, an event in fired in parent page, on body element
* The event is named
*
* fbrowser.<type>.[<eventname>]
*
* <type> will be one of "image" or "file", and the event handler will
* get the following params:
*
* filemane: filename of item choosed by user
* embed: bbcode to embed element into posts
* id: id from caller code
*
* example:
*
* // open dialog for select an image for a textarea with id "myeditor"
* var id="myeditor";
* Dialog.doImageBrowser("example", id);
*
* // setup event handler to get user selection
* $("body").on("fbrowser.image.example", function(event, filename, bbcode, id) {
* // close colorbox
* $.colorbox.close();
* // replace textxarea text with bbcode
* $(id).value = bbcode;
* });
**/
/*
* IMPORTANT
*
* This is a modified version to work with
* the frio theme.and bootstrap modals
*
* The origninal file is under:
* js/filebrowser.js
*
*/
var FileBrowser = {
nickname : "",
type : "",
event: "",
id : null,
init: function(nickname, type, hash) {
FileBrowser.nickname = nickname;
FileBrowser.type = type;
FileBrowser.event = "fbrowser."+type;
if (hash!=="") {
var h = hash.replace("#","");
var destination = h.split("-")[0];
FileBrowser.id = h.split("-")[1];
FileBrowser.event = FileBrowser.event + "." + destination;
if (destination == "comment") {
// get the comment textimput field
var commentElm = document.getElementById("comment-edit-text-" + FileBrowser.id);
}
};
console.log("FileBrowser:", nickname, type,FileBrowser.event, FileBrowser.id );
$(".error a.close").on("click", function(e) {
e.preventDefault();
$(".error").addClass("hidden");
});
$(".folders a, .path a").on("click", function(e){
e.preventDefault();
var url = baseurl + "/fbrowser/" + FileBrowser.type + "/" + this.dataset.folder + "?mode=none";
// load new content to fbrowser window
$(".fbrowser").load(url,function(){
$(function() {FileBrowser.init(nickname, type, hash);});
});
});
//embed on click
$(".photo-album-photo-link").on('click', function(e){
e.preventDefault();
var embed = "";
if (FileBrowser.type == "image") {
embed = "[url="+this.dataset.link+"][img]"+this.dataset.img+"[/img][/url]";
}
if (FileBrowser.type=="file") {
// attachment links are "baseurl/attach/id"; we need id
embed = "[attachment]"+this.dataset.link.split("/").pop()+"[/attachment]";
}
// Delete prefilled Text of the comment input
// Note: not the best solution but function commentOpenUI don't
// work as expected (we need a way to wait until commentOpenUI would be finished).
// As for now we insert pieces of this function here
if ((commentElm !== null) && (typeof commentElm !== "undefined")) {
if (commentElm.value == aStr.comment){
commentElm.value = "";
$("#comment-edit-text-" + FileBrowser.id).addClass("comment-edit-text-full").removeClass("comment-edit-text-empty");
$("#comment-edit-submit-wrapper-" + FileBrowser.id).show();
$("#comment-edit-text-" + FileBrowser.id).attr('tabindex','9');
$("#comment-edit-submit-" + FileBrowser.id).attr('tabindex','10');
}
}
console.log(FileBrowser.event, this.dataset.filename, embed, FileBrowser.id);
parent.$("body").trigger(FileBrowser.event, [
this.dataset.filename,
embed,
FileBrowser.id,
this.dataset.img
]);
// close model
$('#modal').modal('hide');
// if (id!=="") {
// commentExpand(FileBrowser.id);
// //$("#comment-edit-text-558").empty();
// };
});
if ($("#upload-image").length)
var image_uploader = new window.AjaxUpload(
'upload-image',
{ action: 'wall_upload/'+FileBrowser.nickname+'?response=json',
name: 'userfile',
responseType: 'json',
onSubmit: function(file,ext) { $('#profile-rotator').show(); $(".error").addClass('hidden'); },
onComplete: function(file,response) {
if (response['error']!= undefined) {
$(".error span").html(response['error']);
$(".error").removeClass('hidden');
$('#profile-rotator').hide();
return;
}
// location = baseurl + "/fbrowser/image/?mode=none"+location['hash'];
// location.reload(true);
var url = baseurl + "/fbrowser/" + FileBrowser.type + "?mode=none"
// load new content to fbrowser window
$(".fbrowser").load(url,function(){
$(function() {FileBrowser.init(nickname, type, hash);});
});
}
}
);
if ($("#upload-file").length)
var file_uploader = new window.AjaxUpload(
'upload-file',
{ action: 'wall_attach/'+FileBrowser.nickname+'?response=json',
name: 'userfile',
onSubmit: function(file,ext) { $('#profile-rotator').show(); $(".error").addClass('hidden'); },
onComplete: function(file,response) {
if (response['error']!= undefined) {
$(".error span").html(response['error']);
$(".error").removeClass('hidden');
$('#profile-rotator').hide();
return;
}
// location = baseurl + "/fbrowser/file/?mode=none"+location['hash'];
// location.reload(true);
var url = baseurl + "/fbrowser/" + FileBrowser.type + "?mode=none"
// load new content to fbrowser window
$(".fbrowser").load(url,function(){
$(function() {FileBrowser.init(nickname, type, hash);});
});
}
}
);
},
};

View file

@ -0,0 +1,318 @@
/*
* The javascript for friendicas hovercard. Bootstraps popover is needed.
*
* Much parts of the code are from Hannes Mannerheims <h@nnesmannerhe.im>
* qvitter code (https://github.com/hannesmannerheim/qvitter)
*
* It is licensed under the GNU Affero General Public License <http://www.gnu.org/licenses/>
*
*/
$(document).ready(function(){
// Elements with the class "userinfo" will get a hover-card.
// Note that this elements does need a href attribute which links to
// a valid profile url
$("body").on("mouseover", ".userinfo", function(e) {
var timeNow = new Date().getTime();
removeAllhoverCards(e,timeNow);
var hoverCardData = false;
var hrefAttr = false;
var targetElement = $(this);
// get href-attribute
if(targetElement.is('[href]')) {
hrefAttr = targetElement.attr('href');
} else {
return true;
}
// no hover card if the element has the no-hover-card class
if(targetElement.hasClass('no-hover-card')) {
return true;
}
// no hovercard for anchor links
if(hrefAttr.substring(0,1) == '#') {
return true;
}
targetElement.attr('data-awaiting-hover-card',timeNow);
// Take link href attribute as link to the profile
var profileurl = hrefAttr;
// the url to get the contact and template data
var url = baseurl + "/frio_hovercard";
// store the title in an other data attribute beause bootstrap
// popover destroys the title.attribute. We can restore it later
var title = targetElement.attr("title");
targetElement.attr({"data-orig-title": title, title: ""});
// Timeoute until the hover-card does appear
setTimeout(function(){
if(targetElement.is(":hover") && parseInt(targetElement.attr('data-awaiting-hover-card'),10) == timeNow) {
if($('.hovercard').length == 0) { // no card if there already is one open
// get an additional data atribute if the card is active
targetElement.attr('data-hover-card-active',timeNow);
// get the whole html content of the hover card and
// push it to the bootstrap popover
getHoverCardContent(profileurl, url, function(data){
if(data) {
targetElement.popover({
html: true,
placement: function () {
// Calculate the placement of the the hovercard (if top or bottom)
// The placement depence on the distance between window top and the element
// which triggers the hover-card
var get_position = $(targetElement).offset().top - $(window).scrollTop();
if (get_position < 270 ){
return "bottom";
}
return "top";
},
trigger: 'manual',
template: '<div class="popover hovercard" data-card-created="' + timeNow + '"><div class="arrow"></div><div class="popover-content hovercard-content"></div></div>',
content: data
}).popover('show');
}
});
}
}
}, 500);
}).on("mouseleave", ".userinfo", function(e) { // action when mouse leaves the hover-card
var timeNow = new Date().getTime();
// copy the original title to the title atribute
var title = $(this).attr("data-orig-title");
$(this).attr({"data-orig-title": "", title: title});
removeAllhoverCards(e,timeNow);
});
// hover cards should be removed very easily, e.g. when any of these events happen
$('body').on("mouseleave touchstart scroll click dblclick mousedown mouseup submit keydown keypress keyup", function(e){
var timeNow = new Date().getTime();
removeAllhoverCards(e,timeNow);
});
// if we're hovering a hover card, give it a class, so we don't remove it
$('body').on('mouseover','.hovercard', function(e) {
$(this).addClass('dont-remove-card');
});
$('body').on('mouseleave','.hovercard', function(e) {
$(this).removeClass('dont-remove-card');
$(this).popover("hide");
});
}); // End of $(document).ready
// removes all hover cards
function removeAllhoverCards(event,priorTo) {
// don't remove hovercards until after 100ms, so user have time to move the cursor to it (which gives it the dont-remove-card class)
setTimeout(function(){
$.each($('.hovercard'),function(){
var title = $(this).attr("data-orig-title");
// don't remove card if it was created after removeAllhoverCards() was called
if($(this).data('card-created') < priorTo) {
// don't remove it if we're hovering it right now!
if(!$(this).hasClass('dont-remove-card')) {
$('[data-hover-card-active="' + $(this).data('card-created') + '"]').removeAttr('data-hover-card-active');
$(this).popover("hide");
}
}
});
},100);
}
// Ajax request to get json contact data
function getContactData(purl, url, actionOnSuccess) {
var postdata = {
mode : 'none',
profileurl : purl,
datatype : 'json',
};
// Normalize and clean the profile so we can use a standardized url
// as key for the cache
var nurl = cleanContactUrl(purl).normalizeLink();
// If the contact is allready in the cache use the cached result instead
// of doing a new ajax request
if(nurl in getContactData.cache) {
setTimeout(function() { actionOnSuccess(getContactData.cache[nurl]); } , 1);
return;
}
$.ajax({
url: url,
data: postdata,
dataType: "json",
success: function(data, textStatus, request){
// Check if the nurl (normalized profile url) is present and store it to the cache
// The nurl will be the identifier in the object
if(data.nurl.length > 0) {
// Test if the contact is allready connected with the user (if url containing
// the expression ("redir/") We will store different cache keys
if((data.url.search("redir/")) >= 0 ) {
var key = data.url;
} else {
var key = data.nurl;
}
getContactData.cache[key] = data;
}
actionOnSuccess(data, url, request);
},
error: function(data) {
actionOnSuccess(false, data, url);
}
});
}
getContactData.cache = {};
// Get hover-card template data and the contact-data and transform it with
// the help of jSmart. At the end we have full html content of the hovercard
function getHoverCardContent(purl, url, callback) {
// fetch the raw content of the template
getHoverCardTemplate(url, function(stpl) {
var template = unescape(stpl);
// get the contact data
getContactData (purl, url, function(data) {
if(typeof template != 'undefined') {
// get the hover-card variables
var variables = getHoverCardVariables(data);
var tpl;
// use friendicas template delimiters instead of
// the original one
jSmart.prototype.left_delimiter = '{{';
jSmart.prototype.right_delimiter = '}}';
// create a new jSmart instant with the raw content
// of the template
var tpl = new jSmart (template);
// insert the variables content into the template content
var HoverCardContent = tpl.fetch(variables);
callback(HoverCardContent);
}
});
});
// This is interisting. this pice of code ajax request are done asynchron.
// To make it work getHOverCardTemplate() and getHOverCardData have to return it's
// data (no succes handler for each of this). I leave it here, because it could be useful.
// https://lostechies.com/joshuaflanagan/2011/10/20/coordinating-multiple-ajax-requests-with-jquery-when/
// $.when(
// getHoverCardTemplate(url),
// getContactData (term, url )
//
// ).done(function(template, profile){
// if(typeof template != 'undefined') {
// var variables = getHoverCardVariables(profile);
//
// jSmart.prototype.left_delimiter = '{{';
// jSmart.prototype.right_delimiter = '}}';
// var tpl = new jSmart (template);
// var html = tpl.fetch(variables);
//
// return html;
// }
// });
}
// Ajax request to get the raw template content
function getHoverCardTemplate (url, callback) {
var postdata = {
mode: 'none',
datatype: 'tpl'
};
// Look if we have the template already in the cace, so we don't have
// request it again
if('hovercard' in getHoverCardTemplate.cache) {
setTimeout(function() { callback(getHoverCardTemplate.cache['hovercard']); } , 1);
return;
}
$.ajax({
url: url,
data: postdata,
success: function(data, textStatus) {
// write the data in the cache
getHoverCardTemplate.cache['hovercard'] = data;
callback(data);
}
}).fail(function () {callback([]); });
}
getHoverCardTemplate.cache = {};
// The Variables used for the template
function getHoverCardVariables(object) {
var profile = {
name: object.name,
nick: object.nick,
addr: object.addr,
thumb: object.thumb,
url: object.url,
nurl: object.nurl,
location: object.location,
gender: object.gender,
about: object.about,
network: object.network,
tags: object.tags,
bd: object.bd,
account_type: object.account_type,
actions: object.actions
};
var variables = { profile: profile};
return variables;
}
// This is the html template for the hover-card
// Since we grab the original hovercard.tpl we don't
// need it anymore
function hovercard_template() {
var tempate = '\
<div class="basic-content" >\
<div class="hover-card-details">\
<div class="hover-card-header left-align">\
<div class="hover-card-pic left-align">\
<span class="image-wrapper medium">\
<a href="{{$profile.url}}" title="{{$profile.name}}"><img href="" class="left-align thumbnail" src="{{$profile.thumb}}"></a>\
</span>\
</div>\
<div class="hover-card-content">\
<div class="profile-entry-name">\
<h4 class="left-align1"><a href="{{$profile.url}}">{{$profile.name}}</a></h4>{{if $profile.account_type}}<span>{{$profile.account_type}}</span>{{/if}}\
</div>\
<div class="profile-details">\
<span class="profile-addr">{{$profile.addr}}</span>\
{{if $profile.network}}<span class="profile-network"> ({{$profile.network}})</span>{{/if}}\
</div>\
{{*{{if $profile.about}}<div class="profile-details profile-about">{{$profile.about}}</div>{{/if}}*}}\
\
</div>\
<div class="hover-card-actions right-aligned">\
{{* here are the differnt actions like privat message, poke, delete and so on *}}\
{{* @todo we have two different photo menus one for contacts and one for items at the network stream. We currently use the contact photo menu, so the items options are missing We need to move them *}}\
<div class="hover-card-actions-social">\
{{if $profile.actions.pm}}<a class="btn btn-labeled btn-primary btn-sm" onclick="addToModal("{{$profile.actions.pm.1}}")" title="{{$profile.actions.pm.0}}"><i class="fa fa-envelope" aria-hidden="true"></i></a>{{/if}}\
{{if $profile.actions.poke}}<a class="btn btn-labeled btn-primary btn-sm" onclick="addToModal("{{$profile.actions.poke.1}}")" title="{{$profile.actions.poke.0}}"><i class="fa fa-heartbeat" aria-hidden="true"></i></a>{{/if}}\
</div>\
<div class="hover-card-actions-connection">\
{{if $profile.actions.edit}}<a class="btn btn-labeled btn-primary btn-sm" href="{{$profile.actions.edit.1}}" title="{{$profile.actions.edit.0}}"><i class="fa fa-pencil" aria-hidden="true"></i></a>{{/if}}\
{{if $profile.actions.drop}}<a class="btn btn-labeled btn-primary btn-sm" href="{{$profile.actions.drop.1}}" title="{{$profile.actions.drop.0}}"><i class="fa fa-user-times" aria-hidden="true"></i></a>{{/if}}\
{{if $profile.actions.follow}}<a class="btn btn-labeled btn-primary btn-sm" href="{{$profile.actions.follow.1}}" title="{{$profile.actions.follow.0}}"><i class="fa fa-user-plus" aria-hidden="true"></i></a>{{/if}}\
</div>\
</div>\
</div>\
\
<div class="clearfix"></div>\
\
</div>\
</div>\
{{if $profile.tags}}<div class="hover-card-footer">{{$profile.tags}}</div>{{/if}}';
}

259
view/theme/frio/js/modal.js Normal file
View file

@ -0,0 +1,259 @@
/*
* @brief contains functions for bootstrap modal handling
*/
$(document).ready(function(){
// Clear bs modal on close
// We need this to prevent that the modal displays old content
$('body, footer').on('hidden.bs.modal', '.modal', function () {
$(this).removeData('bs.modal');
$("#modal-title").empty();
$('#modal-body').empty();
// remove the file browser from jot (else we would have problems
// with ajaxupload
$(".fbrowser").remove();
});
// Add Colorbox for viewing Network page images
//var cBoxClasses = new Array();
$("body").on("click", ".wall-item-body a img", function(){
var aElem = $(this).parent();
var imgHref = aElem.attr("href");
// We need to make sure we only put a Colorbox on links to Friendica images
// We'll try to do this by looking for links of the form
// .../photo/ab803d8eg08daf85023adfec08 (with nothing more following), in hopes
// that that will be unique enough
if(imgHref.match(/\/photo\/[a-fA-F0-9]+(-[0-9]\.[\w]+?)?$/)) {
// Add a unique class to all the images of a certain post, to allow scrolling through
var cBoxClass = $(this).closest(".wall-item-body").attr("id") + "-lightbox";
$(this).addClass(cBoxClass);
// if( $.inArray(cBoxClass, cBoxClasses) < 0 ) {
// cBoxClasses.push(cBoxClass);
// }
aElem.colorbox({
maxHeight: '90%',
photo: true, // Colorbox doesn't recognize a URL that don't end in .jpg, etc. as a photo
rel: cBoxClass //$(this).attr("class").match(/wall-item-body-[\d]+-lightbox/)[0]
});
}
});
// Jot nav menu.
$("body").on("click", "#jot-modal .jot-nav li a", function(e){
e.preventDefault();
toggleJotNav(this);
});
// Open filebrowser for elements with the class "image-select"
// The following part handles the filebrowser for field_fileinput.tpl
$("body").on("click", ".image-select", function(e){
// set a extra attribute to mark the clicked button
this.setAttribute("image-input", "select");
Dialog.doImageBrowser("input");
});
// Insert filebrowser images into the input field (field_fileinput.tpl)
$("body").on("fbrowser.image.input", function(e, filename, embedcode, id, img) {
// select the clicked button by it's attribute
var elm = $("[image-input='select']")
// select the input field which belongs to this button
var input = elm.parent(".input-group").children("input");
// remove the special indicator attribut from the button
elm.removeAttr("image-input");
// inserte the link from the image into the input field
input.val(img);
});
});
// overwrite Dialog.show from main js to load the filebrowser into a bs modal
Dialog.show = function(url) {
var modal = $('#modal').modal();
modal
.find('#modal-body')
.load(url, function (responseText, textStatus) {
if ( textStatus === 'success' ||
textStatus === 'notmodified')
{
modal.show();
$(function() {Dialog._load(url);});
}
});
};
// overwrite the function _get_url from main.js
Dialog._get_url = function(type, name, id) {
var hash = name;
if (id !== undefined) hash = hash + "-" + id;
return "fbrowser/"+type+"/?mode=none#"+hash;
};
// does load the filebrowser into the jot modal
Dialog.showJot = function() {
var type = "image";
var name = "main";
var url = Dialog._get_url(type, name);
if(($(".modal-body #jot-fbrowser-wrapper .fbrowser").length) < 1 ) {
// load new content to fbrowser window
$("#jot-fbrowser-wrapper").load(url,function(responseText, textStatus){
if ( textStatus === 'success' ||
textStatus === 'notmodified')
{
$(function() {Dialog._load(url);});
}
});
}
};
// init the filebrowser after page load
Dialog._load = function(url) {
// get nickname & filebrowser type from the modal content
var nickname = $("#fb-nickname").attr("value");
var type = $("#fb-type").attr("value");
// try to fetch the hash form the url
var match = url.match(/fbrowser\/[a-z]+\/\?mode=none(.*)/);
var hash = match[1];
// initialize the filebrowser
var jsbrowser = function() {
FileBrowser.init(nickname, type, hash);
}
loadScript("view/theme/frio/js/filebrowser.js", jsbrowser);
};
/**
* @brief Add first h3 element as modal title
*
* Note: this should be really done in the template
* and is the solution where we havent done it until this
* moment or where it isn't possible because of design
*/
function loadModalTitle() {
// clear the text of the title
//$("#modal-title").empty();
// hide the first h3 child element of the modal body
$("#modal-body .heading").first().hide();
// get the text of the first element with heading class
var title = $("#modal-body .heading").first().text();
// and append it to modal title
if (title!=="") {
$("#modal-title").append(title);
}
}
// This function loads html content from a friendica page
// into a modal
function addToModal(url) {
var char = qOrAmp(url);
var url = url + char + 'mode=none';
var modal = $('#modal').modal();
modal
.find('#modal-body')
.load(url, function (responseText, textStatus) {
if ( textStatus === 'success' ||
textStatus === 'notmodified')
{
modal.show();
//Get first h3 element and use it as title
loadModalTitle();
}
});
};
// function to load the html from the edit post page into
// the jot modal
function editpost(url) {
var modal = $('#jot-modal').modal();
var url = url + " #profile-jot-form";
//var rand_num = random_digits(12);
$(".jot-nav #jot-perms-lnk").parent("li").hide();
// rename the the original div jot-preview-content because the edit function
// does load the content for the modal from another source and preview won't work
// if this div would exist twice
// $("#jot-content #profile-jot-form").attr("id","#profile-jot-form-renamed");
// $("#jot-content #jot-preview-content").attr("id","#jot-preview-content-renamed");
// For editpost we load the modal html form the edit page. So we would have two jot forms in
// the page html. To avoid js conflicts we move the original jot to the end of the page
// so the editpost jot would be the first jot in html structure.
// After closing the modal we move the original jot back to it's orginal position in the html structure.
//
// Note: For now it seems to work but this isn't optimal because we have doubled ID names for the jot div's.
// We need to have a better solution for this in the future.
$("section #jot-content #profile-jot-form").appendTo("footer #cache-container");
jotreset();
modal
.find('#jot-modal-body')
.load(url, function (responseText, textStatus) {
if ( textStatus === 'success' ||
textStatus === 'notmodified')
{
// get the item type and hide the input for title and category if it isn't needed
var type = $(responseText).find("#profile-jot-form input[name='type']").val();
if(type === "wall-comment" || type === "remote-comment")
{
$("#profile-jot-form #jot-title-wrap").hide();
$("#profile-jot-form #jot-category-wrap").hide();
}
modal.show();
$("#jot-popup").show();
}
});
}
// remove content from the jot modal
function jotreset() {
// Clear bs modal on close
// We need this to prevent that the modal displays old content
$('body').on('hidden.bs.modal', '#jot-modal', function () {
$(this).removeData('bs.modal');
$(".jot-nav #jot-perms-lnk").parent("li").show();
$("#profile-jot-form #jot-title-wrap").show();
$("#profile-jot-form #jot-category-wrap").show();
// the following was commented out because it is needed anymore
// because we changed the behavior at an other place
// var rand_num = random_digits(12);
// $('#jot-title, #jot-category, #profile-jot-text').val("");
// $( "#profile-jot-form input[name='type']" ).val("wall");
// $( "#profile-jot-form input[name='post_id']" ).val("");
// $( "#profile-jot-form input[name='post_id_random']" ).val(rand_num);
$("#jot-modal-body").empty();
// rename the div #jot-preview-content-renamed back to it's original
// name. Have a look at function editpost() for further explanation
//$("#jot-content #profile-jot-form-renamed").attr("id","#profile-jot-form");
//$("#jot-content #jot-preview-content-renamed").attr("id","#jot-preview-content");
// Move the original jot back to it's old place in the html structure
// For explaination have a look at function editpost()
$("footer #cache-container #profile-jot-form").appendTo("section #jot-content");
});
}
// Give the active "jot-nav" list element the class "active"
function toggleJotNav (elm) {
// select all li of jot-nav and remove the active class
$(elm).closest(".jot-nav").children("li").removeClass("active");
// add the active class to the parent of the link which was selected
$(elm).parent("li").addClass("active");
}

View file

@ -0,0 +1,195 @@
/*
* @brief The file contains functions for text editing and commenting
*/
function insertFormatting(comment,BBcode,id) {
var tmpStr = $("#comment-edit-text-" + id).val();
if(tmpStr == comment) {
tmpStr = "";
$("#comment-edit-text-" + id).addClass("comment-edit-text-full");
$("#comment-edit-text-" + id).removeClass("comment-edit-text-empty");
openMenu("comment-edit-submit-wrapper-" + id);
$("#comment-edit-text-" + id).val(tmpStr);
}
textarea = document.getElementById("comment-edit-text-" +id);
if (document.selection) {
textarea.focus();
selected = document.selection.createRange();
if (BBcode == "url"){
selected.text = "["+BBcode+"]" + "http://" + selected.text + "[/"+BBcode+"]";
} else
selected.text = "["+BBcode+"]" + selected.text + "[/"+BBcode+"]";
} else if (textarea.selectionStart || textarea.selectionStart == "0") {
var start = textarea.selectionStart;
var end = textarea.selectionEnd;
if (BBcode == "url"){
textarea.value = textarea.value.substring(0, start) + "["+BBcode+"]" + "http://" + textarea.value.substring(start, end) + "[/"+BBcode+"]" + textarea.value.substring(end, textarea.value.length);
} else
textarea.value = textarea.value.substring(0, start) + "["+BBcode+"]" + textarea.value.substring(start, end) + "[/"+BBcode+"]" + textarea.value.substring(end, textarea.value.length);
}
return true;
}
function showThread(id) {
$("#collapsed-comments-" + id).show()
$("#collapsed-comments-" + id + " .collapsed-comments").show()
}
function hideThread(id) {
$("#collapsed-comments-" + id).hide()
$("#collapsed-comments-" + id + " .collapsed-comments").hide()
}
function cmtBbOpen(id) {
$("#comment-edit-bb-" + id).show();
}
function cmtBbClose(id) {
$("#comment-edit-bb-" + id).hide();
}
function commentExpand(id) {
$("#comment-edit-text-" + id).value = '';
$("#comment-edit-text-" + id).addClass("comment-edit-text-full");
$("#comment-edit-text-" + id).removeClass("comment-edit-text-empty");
$("#comment-edit-text-" + id).focus();
$("#mod-cmnt-wrap-" + id).show();
openMenu("comment-edit-submit-wrapper-" + id);
return true;
}
function commentClose(obj,id) {
if(obj.value == '') {
obj.value = aStr.comment;
$("#comment-edit-text-" + id).removeClass("comment-edit-text-full");
$("#comment-edit-text-" + id).addClass("comment-edit-text-empty");
$("#mod-cmnt-wrap-" + id).hide();
closeMenu("comment-edit-submit-wrapper-" + id);
return true;
}
return false;
}
function showHideCommentBox(id) {
if( $('#comment-edit-form-' + id).is(':visible')) {
$('#comment-edit-form-' + id).hide();
}
else {
$('#comment-edit-form-' + id).show();
}
}
function commentOpenUI(obj, id) {
$(document).unbind( "click.commentOpen", handler );
var handler = function() {
if(obj.value == aStr.comment) {
obj.value = '';
$("#comment-edit-text-" + id).addClass("comment-edit-text-full").removeClass("comment-edit-text-empty");
// Choose an arbitrary tab index that's greater than what we're using in jot (3 of them)
// The submit button gets tabindex + 1
$("#comment-edit-text-" + id).attr('tabindex','9');
$("#comment-edit-submit-" + id).attr('tabindex','10');
$("#comment-edit-submit-wrapper-" + id).show();
}
};
$(document).bind( "click.commentOpen", handler );
}
function commentCloseUI(obj, id) {
$(document).unbind( "click.commentClose", handler );
var handler = function() {
if(obj.value === '') {
obj.value = aStr.comment;
$("#comment-edit-text-" + id).removeClass("comment-edit-text-full").addClass("comment-edit-text-empty");
$("#comment-edit-text-" + id).removeAttr('tabindex');
$("#comment-edit-submit-" + id).removeAttr('tabindex');
$("#comment-edit-submit-wrapper-" + id).hide();
}
};
$(document).bind( "click.commentClose", handler );
}
// test if there is default content in the jot text box and remove it
function jotTextOpenUI(obj) {
if(obj.value == aStr.share) {
obj.value = '';
$(".modal-body #profile-jot-text").addClass("profile-jot-text-full").removeClass("profile-jot-text-empty");
}
}
// insert default content into the jot text box
// if it's empty
function jotTextCloseUI(obj) {
if(obj.value === '') {
obj.value = aStr.share;
$(".modal-body #profile-jot-text").removeClass("profile-jot-text-full").addClass("profile-jot-text-empty");
}
}
function commentOpen(obj,id) {
if(obj.value == aStr.comment) {
obj.value = '';
$("#comment-edit-text-" + id).addClass("comment-edit-text-full");
$("#comment-edit-text-" + id).removeClass("comment-edit-text-empty");
$("#mod-cmnt-wrap-" + id).show();
openMenu("comment-edit-submit-wrapper-" + id);
return true;
}
return false;
}
function commentInsert(obj,id) {
var tmpStr = $("#comment-edit-text-" + id).val();
if(tmpStr == aStr.comment) {
tmpStr = '';
$("#comment-edit-text-" + id).addClass("comment-edit-text-full");
$("#comment-edit-text-" + id).removeClass("comment-edit-text-empty");
openMenu("comment-edit-submit-wrapper-" + id);
}
var ins = $(obj).html();
ins = ins.replace('&lt;','<');
ins = ins.replace('&gt;','>');
ins = ins.replace('&amp;','&');
ins = ins.replace('&quot;','"');
$("#comment-edit-text-" + id).val(tmpStr + ins);
}
function qCommentInsert(obj,id) {
var tmpStr = $("#comment-edit-text-" + id).val();
if(tmpStr == aStr.comment) {
tmpStr = '';
$("#comment-edit-text-" + id).addClass("comment-edit-text-full");
$("#comment-edit-text-" + id).removeClass("comment-edit-text-empty");
openMenu("comment-edit-submit-wrapper-" + id);
}
var ins = $(obj).val();
ins = ins.replace('&lt;','<');
ins = ins.replace('&gt;','>');
ins = ins.replace('&amp;','&');
ins = ins.replace('&quot;','"');
$("#comment-edit-text-" + id).val(tmpStr + ins);
$(obj).val('');
}
function confirmDelete() { return confirm(aStr.delitem); }
function dropItem(url, object) {
var confirm = confirmDelete();
if(confirm) {
$('body').css('cursor', 'wait');
$(object).fadeTo('fast', 0.33, function () {
$.get(url).done(function() {
$(object).remove();
$('body').css('cursor', 'auto');
});
});
}
}

459
view/theme/frio/js/theme.js Normal file
View file

@ -0,0 +1,459 @@
$(document).ready(function(){
//fade in/out based on scrollTop value
$(window).scroll(function () {
if ($(this).scrollTop() > 1000) {
$("#back-to-top").fadeIn();
} else {
$("#back-to-top").fadeOut();
}
});
// scroll body to 0px on click
$("#back-to-top").click(function () {
$("body,html").animate({
scrollTop: 0
}, 400);
return false;
});
// add the class "selected" to group widges li if li > a does have the class group-selected
if( $("#sidebar-group-ul li a").hasClass("group-selected")) {
$("#sidebar-group-ul li a.group-selected").parent("li").addClass("selected");
}
// add the class "selected" to forums widges li if li > a does have the class forum-selected
if( $("#forumlist-sidbar-ul li a").hasClass("forum-selected")) {
$("#forumlist-sidbar-ul li a.forum-selected").parent("li").addClass("selected");
}
// add the class "active" to tabmenuli if li > a does have the class active
if( $("#tabmenu ul li a").hasClass("active")) {
$("#tabmenu ul li a.active").parent("li").addClass("active");
}
// give select fields an boostrap classes
// @todo: this needs to be changed in friendica core
$(".field.select, .field.custom").addClass("form-group");
$(".field.select > select, .field.custom > select").addClass("form-control");
// move the tabbar to the second nav bar
if( $("ul.tabbar")) {
$("ul.tabbar").appendTo("#topbar-second > .container > #tabmenu");
}
// add mask css url to the logo-img container
//
// This is for firefox - we use a mask which looks like the friendica logo to apply user collers
// to the friendica logo (the mask is in nav.tpl at the botom). To make it work we need to apply the
// correct url. The only way which comes to my mind was to do this with js
// So we apply the correct url (with the link to the id of the mask) after the page is loaded.
if($("#logo-img")) {
var pageurl = "url('" + window.location.href + "#logo-mask')";
$("#logo-img").css({"mask": pageurl});
}
// make responsive tabmenu with flexmenu.js
// the menupoints which doesn't fit in the second nav bar will moved to a
// dropdown menu. Look at common_tabs.tpl
$("ul.tabs.flex-nav").flexMenu({
'cutoff': 2,
'popupClass': "dropdown-menu pull-right",
'popupAbsolute': false,
'target': ".flex-target"
});
// add Jot botton to the scecond navbar
if( $("section #jotOpen")) {
$("section #jotOpen").appendTo("#topbar-second > .container > #navbar-button");
if( $("#jot-popup").is(":hidden")) $("#topbar-second > .container > #navbar-button #jotOpen").hide();
}
// move shared content in it's own DIV (so we can style it better)
$('.wall-item-body .shared_content').each(function() {
// create a DIV after ".shared_content" where we will putt in the shared_header
// and the "shared_content"
$(this).after('<div class="shared-content-wrapper content-card"></div>');
// get the shared_header
var sheader = $(this).prev();
// get the shared-content-wrapper which we have created above
var swrapper = $(this).next();
// move the "shared_header into the new shared_content DIV
$(swrapper).append(sheader);
// move the "shared_content" into the new DIV
$(swrapper).append(this);
});
// show bulk deletion button at network page if checkbox is checked
$('input.item-select').change(function(){
var checked = false;
// We need to get all checked items, so it would close the delete button
// if we uncheck one item and others are still checked.
// So return checked = true if there is any checked item
$('input.item-select').each( function() {
if($(this).is(':checked')) {
checked = true;
return false;
}
});
if(checked == true) {
$("a#item-delete-selected").fadeTo(400, 1);
$("a#item-delete-selected").show();
} else {
$("a#item-delete-selected").fadeTo(400, 0, function(){
$("a#item-delete-selected").hide();
});
}
});
// add search-heading to the scecond navbar
if( $(".search-heading")) {
$(".search-heading").appendTo("#topbar-second > .container > #tabmenu");
}
//$('ul.flex-nav').flexMenu();
// initialize the bootstrap tooltips
$('body').tooltip({
selector: '[data-toggle="tooltip"]',
animation: true,
html: true,
placement: 'auto',
delay: {
show: 500,
hide: 100
}
});
});
//function commentOpenUI(obj, id) {
// $(document).unbind( "click.commentOpen", handler );
//
// var handler = function() {
// if(obj.value == '{{$comment}}') {
// obj.value = '';
// $("#comment-edit-text-" + id).addClass("comment-edit-text-full").removeClass("comment-edit-text-empty");
// // Choose an arbitrary tab index that's greater than what we're using in jot (3 of them)
// // The submit button gets tabindex + 1
// $("#comment-edit-text-" + id).attr('tabindex','9');
// $("#comment-edit-submit-" + id).attr('tabindex','10');
// $("#comment-edit-submit-wrapper-" + id).show();
// }
// };
//
// $(document).bind( "click.commentOpen", handler );
//}
//
//function commentCloseUI(obj, id) {
// $(document).unbind( "click.commentClose", handler );
//
// var handler = function() {
// if(obj.value === '') {
// obj.value = '{{$comment}}';
// $("#comment-edit-text-" + id).removeClass("comment-edit-text-full").addClass("comment-edit-text-empty");
// $("#comment-edit-text-" + id).removeAttr('tabindex');
// $("#comment-edit-submit-" + id).removeAttr('tabindex');
// $("#comment-edit-submit-wrapper-" + id).hide();
// }
// };
//
// $(document).bind( "click.commentClose", handler );
//}
function openClose(theID) {
var elem = document.getElementById(theID);
if( $(elem).is(':visible')) {
$(elem).slideUp(200);
}
else {
$(elem).slideDown(200);
}
}
function showHide(theID) {
if(document.getElementById(theID).style.display == "block") {
document.getElementById(theID).style.display = "none"
}
else {
document.getElementById(theID).style.display = "block"
}
}
function showHideComments(id) {
if( $('#collapsed-comments-' + id).is(':visible')) {
$('#collapsed-comments-' + id).slideUp();
$('#hide-comments-' + id).html(window.showMore);
$('#hide-comments-total-' + id).show();
}
else {
$('#collapsed-comments-' + id).slideDown();
$('#hide-comments-' + id).html(window.showFewer);
$('#hide-comments-total-' + id).hide();
}
}
function justifyPhotos() {
justifiedGalleryActive = true;
$('#photo-album-contents').justifiedGallery({
margins: 3,
border: 0,
sizeRangeSuffixes: {
'lt100': '-2',
'lt240': '-2',
'lt320': '-2',
'lt500': '',
'lt640': '-1',
'lt1024': '-0'
}
}).on('jg.complete', function(e){ justifiedGalleryActive = false; });
}
function justifyPhotosAjax() {
justifiedGalleryActive = true;
$('#photo-album-contents').justifiedGallery('norewind').on('jg.complete', function(e){ justifiedGalleryActive = false; });
}
function loadScript(url, callback) {
// Adding the script tag to the head as suggested before
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
// Then bind the event to the callback function.
// There are several events for cross browser compatibility.
script.onreadystatechange = callback;
script.onload = callback;
// Fire the loading
head.appendChild(script);
}
function random_digits(digits) {
var rn = "";
var rnd = "";
for(var i = 0; i < digits; i++) {
var rn = Math.round(Math.random() * (9));
rnd += rn;
}
return rnd;
}
// Does we need a ? or a & to append values to a url
function qOrAmp(url) {
if(url.search('\\?') < 0) {
return '?';
} else {
return '&';
}
}
function contact_filter(item) {
// get the html content from the js template of the contact-wrapper
contact_tpl = unescape($(".javascript-template[rel=contact-template]").html());
var variables = {
id: item.id,
name: item.name,
username: item.username,
thumb: item.thumb,
img_hover: item.img_hover,
edit_hover: item.edit_hover,
account_type: item.account_type,
photo_menu: item.photo_menu,
alt_text: item.alt_text,
dir_icon: item.dir_icon,
sparkle: item.sparkle,
itemurl: item.itemurl,
url: item.url,
network: item.network,
tags: item.tags,
details: item.details,
};
// open a new jSmart instance with the template
var tpl = new jSmart (contact_tpl);
// replace the variable with the values
var html = tpl.fetch(variables);
return html;
}
function filter_replace(item) {
return item.name;
}
(function( $ ) {
$.fn.contact_filter = function(backend_url, typ, autosubmit, onselect) {
if(typeof typ === 'undefined') typ = '';
if(typeof autosubmit === 'undefined') autosubmit = false;
// Autocomplete contacts
contacts = {
match: /(^)([^\n]+)$/,
index: 2,
search: function(term, callback) { contact_search(term, callback, backend_url, typ); },
replace: filter_replace,
template: contact_filter,
};
this.attr('autocomplete','off');
var a = this.textcomplete([contacts], {className:'accontacts', appendTo: '#contact-list'});
a.on('textComplete:select', function(e, value, strategy) { $(".dropdown-menu.textcomplete-dropdown.media-list").show(); });
};
})( jQuery );
// current time in milliseconds, to send each request to make sure
// we 're not getting 304 response
function timeNow() {
return new Date().getTime();
}
String.prototype.normalizeLink = function () {
var ret = this.replace('https:', 'http:');
var ret = ret.replace('//www', '//');
return ret.rtrim();
};
function cleanContactUrl(url) {
var parts = parseUrl(url);
if(! ("scheme" in parts) || ! ("host" in parts)) {
return url;
}
var newUrl =parts["scheme"] + "://" + parts["host"];
if("port" in parts) {
newUrl += ":" + parts["port"];
}
if("path" in parts) {
newUrl += parts["path"];
}
// if(url != newUrl) {
// console.log("Cleaned contact url " + url + " to " + newUrl);
// }
return newUrl;
}
function parseUrl (str, component) { // eslint-disable-line camelcase
// discuss at: http://locutusjs.io/php/parse_url/
// original by: Steven Levithan (http://blog.stevenlevithan.com)
// reimplemented by: Brett Zamir (http://brett-zamir.me)
// input by: Lorenzo Pisani
// input by: Tony
// improved by: Brett Zamir (http://brett-zamir.me)
// note 1: original by http://stevenlevithan.com/demo/parseuri/js/assets/parseuri.js
// note 1: blog post at http://blog.stevenlevithan.com/archives/parseuri
// note 1: demo at http://stevenlevithan.com/demo/parseuri/js/assets/parseuri.js
// note 1: Does not replace invalid characters with '_' as in PHP,
// note 1: nor does it return false with
// note 1: a seriously malformed URL.
// note 1: Besides function name, is essentially the same as parseUri as
// note 1: well as our allowing
// note 1: an extra slash after the scheme/protocol (to allow file:/// as in PHP)
// example 1: parse_url('http://user:pass@host/path?a=v#a')
// returns 1: {scheme: 'http', host: 'host', user: 'user', pass: 'pass', path: '/path', query: 'a=v', fragment: 'a'}
// example 2: parse_url('http://en.wikipedia.org/wiki/%22@%22_%28album%29')
// returns 2: {scheme: 'http', host: 'en.wikipedia.org', path: '/wiki/%22@%22_%28album%29'}
// example 3: parse_url('https://host.domain.tld/a@b.c/folder')
// returns 3: {scheme: 'https', host: 'host.domain.tld', path: '/a@b.c/folder'}
// example 4: parse_url('https://gooduser:secretpassword@www.example.com/a@b.c/folder?foo=bar')
// returns 4: { scheme: 'https', host: 'www.example.com', path: '/a@b.c/folder', query: 'foo=bar', user: 'gooduser', pass: 'secretpassword' }
var query
var mode = (typeof require !== 'undefined' ? require('../info/ini_get')('locutus.parse_url.mode') : undefined) || 'php'
var key = [
'source',
'scheme',
'authority',
'userInfo',
'user',
'pass',
'host',
'port',
'relative',
'path',
'directory',
'file',
'query',
'fragment'
]
// For loose we added one optional slash to post-scheme to catch file:/// (should restrict this)
var parser = {
php: new RegExp([
'(?:([^:\\/?#]+):)?',
'(?:\\/\\/()(?:(?:()(?:([^:@\\/]*):?([^:@\\/]*))?@)?([^:\\/?#]*)(?::(\\d*))?))?',
'()',
'(?:(()(?:(?:[^?#\\/]*\\/)*)()(?:[^?#]*))(?:\\?([^#]*))?(?:#(.*))?)'
].join('')),
strict: new RegExp([
'(?:([^:\\/?#]+):)?',
'(?:\\/\\/((?:(([^:@\\/]*):?([^:@\\/]*))?@)?([^:\\/?#]*)(?::(\\d*))?))?',
'((((?:[^?#\\/]*\\/)*)([^?#]*))(?:\\?([^#]*))?(?:#(.*))?)'
].join('')),
loose: new RegExp([
'(?:(?![^:@]+:[^:@\\/]*@)([^:\\/?#.]+):)?',
'(?:\\/\\/\\/?)?',
'((?:(([^:@\\/]*):?([^:@\\/]*))?@)?([^:\\/?#]*)(?::(\\d*))?)',
'(((\\/(?:[^?#](?![^?#\\/]*\\.[^?#\\/.]+(?:[?#]|$)))*\\/?)?([^?#\\/]*))',
'(?:\\?([^#]*))?(?:#(.*))?)'
].join(''))
}
var m = parser[mode].exec(str)
var uri = {}
var i = 14
while (i--) {
if (m[i]) {
uri[key[i]] = m[i]
}
}
if (component) {
return uri[component.replace('PHP_URL_', '').toLowerCase()]
}
if (mode !== 'php') {
var name = (typeof require !== 'undefined' ? require('../info/ini_get')('locutus.parse_url.queryKey') : undefined) || 'queryKey'
parser = /(?:^|&)([^&=]*)=?([^&]*)/g
uri[name] = {}
query = uri[key[12]] || ''
query.replace(parser, function ($0, $1, $2) {
if ($1) {
uri[name][$1] = $2
}
})
}
delete uri.source
return uri
}
// trim function to replace whithespace after the string
String.prototype.rtrim = function() {
var trimmed = this.replace(/\s+$/g, '');
return trimmed;
};