mirror of
https://github.com/twisterarmy/twister-html.git
synced 2025-03-13 05:51:03 +00:00
global fix of mentions autocomleting, upd of jquery.textcomplete
This commit is contained in:
parent
725f26a368
commit
6ad8f87bdd
@ -360,8 +360,9 @@ button.follow:hover, button.unfollow:hover, .following-list button.private:hover
|
|||||||
top: 45px;
|
top: 45px;
|
||||||
right: 10px;
|
right: 10px;
|
||||||
width: 250px;
|
width: 250px;
|
||||||
box-shadow: 0 2px 5px #65686f;
|
|
||||||
border: solid 1px rgba( 69, 71, 77, .1 );
|
border: solid 1px rgba( 69, 71, 77, .1 );
|
||||||
|
border-right: solid 6px rgba( 227, 79, 66, .82 );
|
||||||
|
box-shadow: 8px 10px 15px 0px rgba(0,0,0, .3);
|
||||||
}
|
}
|
||||||
.dialog-modal:after
|
.dialog-modal:after
|
||||||
{
|
{
|
||||||
@ -393,7 +394,7 @@ button.follow:hover, button.unfollow:hover, .following-list button.private:hover
|
|||||||
.userMenu-search-sugestions a:hover,
|
.userMenu-search-sugestions a:hover,
|
||||||
.userMenu-search-profiles li:hover a
|
.userMenu-search-profiles li:hover a
|
||||||
{
|
{
|
||||||
background: #fefef1;
|
background: #fefedf;
|
||||||
}
|
}
|
||||||
.userMenu-search-profiles button
|
.userMenu-search-profiles button
|
||||||
{
|
{
|
||||||
@ -903,19 +904,17 @@ ol.toptrends-list {
|
|||||||
width: 5px;
|
width: 5px;
|
||||||
/*right: -5px;*/
|
/*right: -5px;*/
|
||||||
}
|
}
|
||||||
.post:hover,
|
|
||||||
.post .post
|
|
||||||
{
|
|
||||||
background: #fefef1;
|
|
||||||
}
|
|
||||||
.post:hover
|
.post:hover
|
||||||
{
|
{
|
||||||
|
background: #fefedf;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
.post.open:hover
|
|
||||||
{
|
.post .expanded-post .original {
|
||||||
background: #fff;
|
background: #fefedf;
|
||||||
}
|
}
|
||||||
|
|
||||||
.post-photo,
|
.post-photo,
|
||||||
.mini-profile-photo
|
.mini-profile-photo
|
||||||
{
|
{
|
||||||
@ -2011,44 +2010,31 @@ ol.toptrends-list {
|
|||||||
right: 8px;
|
right: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Autocomplite*/
|
/*************************************
|
||||||
.textcomplete-wrapper textarea {
|
*********** AUTOCOMPLETING ***********
|
||||||
display: inline;
|
**************************************/
|
||||||
}
|
|
||||||
ul.dropdown-menu {
|
ul.dropdown-menu {
|
||||||
position: absolute;
|
|
||||||
top: 23px;
|
|
||||||
left: 170px;
|
|
||||||
z-index: 100;
|
|
||||||
display: block;
|
|
||||||
float: left;
|
|
||||||
min-width: 160px;
|
min-width: 160px;
|
||||||
padding: 5px 0;
|
padding: 0;
|
||||||
margin: 2px 0 0;
|
margin: 0;
|
||||||
list-style: none;
|
list-style: none;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
border: 1px solid rgba(0,0,0, .2);
|
border-radius: 0px;
|
||||||
border-radius: 6px;
|
border: solid 1px rgba( 69, 71, 77, .1 );
|
||||||
-webkit-border-radius: 6px;
|
border-right: solid 4px rgba( 227, 79, 66, .82 );
|
||||||
-moz-border-radius: 6px;
|
box-shadow: 8px 10px 10px 0px rgba(0,0,0, .2);
|
||||||
-webkit-box-shadow: 0 5px 10px rgba(0,0,0, .2);
|
|
||||||
-moz-box-shadow: 0 5px 10px rgba(0,0,0, .2);
|
|
||||||
box-shadow: 0 5px 10px rgba(0,0,0, .2);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ul.dropdown-menu li {
|
ul.dropdown-menu li {
|
||||||
line-height: 20px;
|
|
||||||
|
|
||||||
}
|
|
||||||
ul.dropdown-menu > li > a {
|
|
||||||
display: block;
|
|
||||||
padding: 3px 20px;
|
padding: 3px 20px;
|
||||||
clear: both;
|
|
||||||
font: 13px/20px "Open Sans", sans-serif;
|
font: 13px/20px "Open Sans", sans-serif;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
-webkit-transition: all 200ms;
|
}
|
||||||
-moz-transition: all 200ms;
|
|
||||||
-ms-transition: all 200ms;
|
ul.dropdown-menu li:hover,
|
||||||
-o-transition: all 200ms;
|
ul.dropdown-menu .active, ul.dropdown-menu .active a {
|
||||||
transition: all 200ms;
|
background-color: #fefedf;
|
||||||
|
text-decoration: none;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
<script src="js/twister_directmsg.js"></script>
|
<script src="js/twister_directmsg.js"></script>
|
||||||
<script src="js/twister_actions.js"></script>
|
<script src="js/twister_actions.js"></script>
|
||||||
<script src="js/interface_common.js"></script>
|
<script src="js/interface_common.js"></script>
|
||||||
|
<script src="js/jquery.textcomplete.min.js"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
$(document).ready(function()
|
$(document).ready(function()
|
||||||
|
@ -27,12 +27,11 @@
|
|||||||
<script src="js/twister_directmsg.js"></script>
|
<script src="js/twister_directmsg.js"></script>
|
||||||
<script src="js/interface_common.js"></script>
|
<script src="js/interface_common.js"></script>
|
||||||
<script src="js/interface_home.js"></script>
|
<script src="js/interface_home.js"></script>
|
||||||
<script src="js/jquery.textcomplete.js"></script>
|
<script src="js/jquery.textcomplete.min.js"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
$(function(){setTimeout(mensAutocomplete, 800);})
|
changeStyle();
|
||||||
changeStyle();
|
</script>
|
||||||
</script> <!-- calm init for autocomplete -->
|
|
||||||
|
|
||||||
<link rel="icon" type="image/png" href="img/twister_mini.png" />
|
<link rel="icon" type="image/png" href="img/twister_mini.png" />
|
||||||
</head>
|
</head>
|
||||||
|
@ -28,8 +28,3 @@ $(function(){
|
|||||||
};
|
};
|
||||||
setTimeout(dhtIndicatorBg, 300);
|
setTimeout(dhtIndicatorBg, 300);
|
||||||
setTimeout(function() {setInterval(dhtIndicatorBg, 2000)}, 400);
|
setTimeout(function() {setInterval(dhtIndicatorBg, 2000)}, 400);
|
||||||
|
|
||||||
|
|
||||||
function homeIntInit () {
|
|
||||||
setTimeout(mensAutocomplete, 800);
|
|
||||||
}
|
|
||||||
|
@ -798,7 +798,7 @@ function replyTextKeypress(e) {
|
|||||||
$oldta.on("blur", replyTextKeypress);
|
$oldta.on("blur", replyTextKeypress);
|
||||||
$oldta.addClass('splited-post');
|
$oldta.addClass('splited-post');
|
||||||
|
|
||||||
tweetForm.find(".textcomplete-wrapper").append($newta);
|
tweetForm.find(".textcomplete-wrapper").append($newta); // FIXME come find textcomplete-wrapper anywhere in code
|
||||||
$newta.val(cp.substr(ci));
|
$newta.val(cp.substr(ci));
|
||||||
$newta.focus();
|
$newta.focus();
|
||||||
if ($newta[0].setSelectionRange)
|
if ($newta[0].setSelectionRange)
|
||||||
@ -1393,7 +1393,6 @@ function changeStyle() {
|
|||||||
style = 'theme_nin/css/style.css';
|
style = 'theme_nin/css/style.css';
|
||||||
profile = 'theme_nin/css/profile.css';
|
profile = 'theme_nin/css/profile.css';
|
||||||
$.getScript('theme_nin/js/theme_option.js');
|
$.getScript('theme_nin/js/theme_option.js');
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(theme == 'calm')
|
if(theme == 'calm')
|
||||||
@ -1416,29 +1415,30 @@ function changeStyle() {
|
|||||||
setTimeout(function(){$(menu).removeAttr('style')}, 0);
|
setTimeout(function(){$(menu).removeAttr('style')}, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mensAutocomplete() {
|
function getMentionsForAutoComplete() {
|
||||||
var suggests = [];
|
if (defaultScreenName && typeof(followingUsers) !== 'undefined') {
|
||||||
|
var suggests = followingUsers.slice();
|
||||||
|
|
||||||
for(var i = 0; i < followingUsers.length; i++){
|
if (suggests.indexOf(defaultScreenName) > -1)
|
||||||
if(followingUsers[i] == localStorage.defaultScreenName) continue;
|
suggests.splice(suggests.indexOf(defaultScreenName), 1);
|
||||||
suggests.push(followingUsers[i]);
|
if (suggests.length > 0) {
|
||||||
}
|
suggests.sort();
|
||||||
suggests.reverse();
|
|
||||||
$('textarea').textcomplete([
|
return [{
|
||||||
{ // html
|
mentions: suggests,
|
||||||
mentions: suggests,
|
match: /\B@(\w*)$/,
|
||||||
match: /\B@(\w*)$/,
|
search: function (term, callback) {
|
||||||
search: function (term, callback) {
|
callback($.map(this.mentions, function (mention) {
|
||||||
callback($.map(this.mentions, function (mention) {
|
return mention.indexOf(term) === 0 ? mention : null;
|
||||||
return mention.indexOf(term) === 0 ? mention : null;
|
}));
|
||||||
}));
|
},
|
||||||
},
|
index: 1,
|
||||||
index: 1,
|
replace: function (mention) {
|
||||||
replace: function (mention) {
|
return '@'+mention+' ';
|
||||||
return '@' + mention + ' ';
|
}
|
||||||
|
}];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function replaceDashboards() {
|
function replaceDashboards() {
|
||||||
@ -1485,10 +1485,6 @@ function initInterfaceCommon() {
|
|||||||
});
|
});
|
||||||
*/
|
*/
|
||||||
|
|
||||||
$('.dropdown-menu').on('keydown', function(e){
|
|
||||||
e = event || window.event;
|
|
||||||
e.stopPropagation();
|
|
||||||
})
|
|
||||||
$('.post-text').on('click', 'a', function(e){
|
$('.post-text').on('click', 'a', function(e){
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
});
|
});
|
||||||
@ -1529,4 +1525,42 @@ function initInterfaceCommon() {
|
|||||||
$('.bitmessage-ctc').on('click', function(){
|
$('.bitmessage-ctc').on('click', function(){
|
||||||
window.prompt(polyglot.t('copy_to_clipboard'), $(this).attr('data'))
|
window.prompt(polyglot.t('copy_to_clipboard'), $(this).attr('data'))
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (typeof($.fn.textcomplete) === 'function') {
|
||||||
|
$('textarea')
|
||||||
|
.on('focus', function () {
|
||||||
|
var element = this;
|
||||||
|
// Cursor has not set yet. And wait 100ms to skip global click event.
|
||||||
|
setTimeout(function () {
|
||||||
|
// Cursor is ready.
|
||||||
|
$(element).textcomplete(getMentionsForAutoComplete(), {
|
||||||
|
'appendTo': ($(element).parents('.dashboard').length > 0) ? $(element).parent() : $('body'),
|
||||||
|
'listPosition': setTextcompleteDropdownListPos
|
||||||
|
});
|
||||||
|
}, 100);
|
||||||
|
})
|
||||||
|
.on('focusout', function () {
|
||||||
|
$(this).textcomplete('destroy');
|
||||||
|
})
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// following workaround function is for calls from $.fn.textcomplete only
|
||||||
|
// we need this because currently implementation of caret position detection is way too imperfect
|
||||||
|
|
||||||
|
function setTextcompleteDropdownListPos(position) {
|
||||||
|
position = this._applyPlacement(position);
|
||||||
|
|
||||||
|
if (this.option.appendTo.parents('.dashboard').length > 0) {
|
||||||
|
position['position'] = 'fixed';
|
||||||
|
position['top'] = (parseFloat(position['top']) - window.pageYOffset).toString()+'px';
|
||||||
|
} else {
|
||||||
|
position['position'] = 'absolute';
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$el.css(position);
|
||||||
|
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -1,554 +0,0 @@
|
|||||||
/*!
|
|
||||||
* jQuery.textcomplete.js
|
|
||||||
*
|
|
||||||
* Repositiory: https://github.com/yuku-t/jquery-textcomplete
|
|
||||||
* License: MIT
|
|
||||||
* Author: Yuku Takahashi
|
|
||||||
*/
|
|
||||||
|
|
||||||
;(function ($) {
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exclusive execution control utility.
|
|
||||||
*/
|
|
||||||
var lock = function (func) {
|
|
||||||
var free, locked;
|
|
||||||
free = function () { locked = false; };
|
|
||||||
return function () {
|
|
||||||
var args;
|
|
||||||
if (locked) return;
|
|
||||||
locked = true;
|
|
||||||
args = toArray(arguments);
|
|
||||||
args.unshift(free);
|
|
||||||
func.apply(this, args);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert arguments into a real array.
|
|
||||||
*/
|
|
||||||
var toArray = function (args) {
|
|
||||||
var result;
|
|
||||||
result = Array.prototype.slice.call(args);
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the styles of any element from property names.
|
|
||||||
*/
|
|
||||||
var getStyles = (function () {
|
|
||||||
var color;
|
|
||||||
color = $('<div></div>').css(['color']).color;
|
|
||||||
if (typeof color !== 'undefined') {
|
|
||||||
return function ($el, properties) {
|
|
||||||
return $el.css(properties);
|
|
||||||
};
|
|
||||||
} else { // for jQuery 1.8 or below
|
|
||||||
return function ($el, properties) {
|
|
||||||
var styles;
|
|
||||||
styles = {};
|
|
||||||
$.each(properties, function (i, property) {
|
|
||||||
styles[property] = $el.css(property);
|
|
||||||
});
|
|
||||||
return styles;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default template function.
|
|
||||||
*/
|
|
||||||
var identity = function (obj) { return obj; };
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Memoize a search function.
|
|
||||||
*/
|
|
||||||
var memoize = function (func) {
|
|
||||||
var memo = {};
|
|
||||||
return function (term, callback) {
|
|
||||||
if (memo[term]) {
|
|
||||||
callback(memo[term]);
|
|
||||||
} else {
|
|
||||||
func.call(this, term, function (data) {
|
|
||||||
memo[term] = (memo[term] || []).concat(data);
|
|
||||||
callback.apply(null, arguments);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine if the array contains a given value.
|
|
||||||
*/
|
|
||||||
var include = function (array, value) {
|
|
||||||
var i, l;
|
|
||||||
if (array.indexOf) return array.indexOf(value) != -1;
|
|
||||||
for (i = 0, l = array.length; i < l; i++) {
|
|
||||||
if (array[i] === value) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Textarea manager class.
|
|
||||||
*/
|
|
||||||
var Completer = (function () {
|
|
||||||
var html, css, $baseWrapper, $baseList, _id;
|
|
||||||
|
|
||||||
html = {
|
|
||||||
wrapper: '<div class="textcomplete-wrapper"></div>',
|
|
||||||
list: '<ul class="dropdown-menu"></ul>'
|
|
||||||
};
|
|
||||||
css = {
|
|
||||||
wrapper: {
|
|
||||||
position: 'relative'
|
|
||||||
},
|
|
||||||
list: {
|
|
||||||
position: 'absolute',
|
|
||||||
top: 0,
|
|
||||||
left: 0,
|
|
||||||
zIndex: '100',
|
|
||||||
display: 'none'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
$baseWrapper = $(html.wrapper).css(css.wrapper);
|
|
||||||
$baseList = $(html.list).css(css.list);
|
|
||||||
_id = 0;
|
|
||||||
|
|
||||||
function Completer($el) {
|
|
||||||
var focus;
|
|
||||||
this.el = $el.get(0); // textarea element
|
|
||||||
focus = this.el === document.activeElement;
|
|
||||||
// Cannot wrap $el at initialize method lazily due to Firefox's behavior.
|
|
||||||
this.$el = wrapElement($el); // Focus is lost
|
|
||||||
this.id = 'textComplete' + _id++;
|
|
||||||
this.strategies = [];
|
|
||||||
if (focus) {
|
|
||||||
this.initialize();
|
|
||||||
this.$el.focus();
|
|
||||||
} else {
|
|
||||||
this.$el.one('focus.textComplete', $.proxy(this.initialize, this));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Completer's public methods
|
|
||||||
*/
|
|
||||||
$.extend(Completer.prototype, {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prepare ListView and bind events.
|
|
||||||
*/
|
|
||||||
initialize: function () {
|
|
||||||
var $list, globalEvents;
|
|
||||||
$list = $baseList.clone();
|
|
||||||
this.listView = new ListView($list, this);
|
|
||||||
this.$el
|
|
||||||
.before($list)
|
|
||||||
.on({
|
|
||||||
'keyup.textComplete': $.proxy(this.onKeyup, this),
|
|
||||||
'keydown.textComplete': $.proxy(this.listView.onKeydown,
|
|
||||||
this.listView)
|
|
||||||
});
|
|
||||||
globalEvents = {};
|
|
||||||
globalEvents['click.' + this.id] = $.proxy(this.onClickDocument, this);
|
|
||||||
globalEvents['keyup.' + this.id] = $.proxy(this.onKeyupDocument, this);
|
|
||||||
$(document).on(globalEvents);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register strategies to the completer.
|
|
||||||
*/
|
|
||||||
register: function (strategies) {
|
|
||||||
this.strategies = this.strategies.concat(strategies);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show autocomplete list next to the caret.
|
|
||||||
*/
|
|
||||||
renderList: function (data) {
|
|
||||||
if (this.clearAtNext) {
|
|
||||||
this.listView.clear();
|
|
||||||
this.clearAtNext = false;
|
|
||||||
}
|
|
||||||
if (data.length) {
|
|
||||||
if (!this.listView.shown) {
|
|
||||||
this.listView
|
|
||||||
.setPosition(this.getCaretPosition())
|
|
||||||
.clear()
|
|
||||||
.activate();
|
|
||||||
this.listView.strategy = this.strategy;
|
|
||||||
}
|
|
||||||
data = data.slice(0, this.strategy.maxCount);
|
|
||||||
this.listView.render(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.listView.data.length && this.listView.shown) {
|
|
||||||
this.listView.deactivate();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
searchCallbackFactory: function (free) {
|
|
||||||
var self = this;
|
|
||||||
return function (data, keep) {
|
|
||||||
self.renderList(data);
|
|
||||||
if (!keep) {
|
|
||||||
// This is the last callback for this search.
|
|
||||||
free();
|
|
||||||
self.clearAtNext = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Keyup event handler.
|
|
||||||
*/
|
|
||||||
onKeyup: function (e) {
|
|
||||||
var searchQuery, term;
|
|
||||||
if (this.skipSearch(e)) { return; }
|
|
||||||
|
|
||||||
searchQuery = this.extractSearchQuery(this.getTextFromHeadToCaret());
|
|
||||||
if (searchQuery.length) {
|
|
||||||
term = searchQuery[1];
|
|
||||||
if (this.term === term) return; // Ignore shift-key or something.
|
|
||||||
this.term = term;
|
|
||||||
this.search(searchQuery);
|
|
||||||
} else {
|
|
||||||
this.term = null;
|
|
||||||
this.listView.deactivate();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Suppress searching if it returns true.
|
|
||||||
*/
|
|
||||||
skipSearch: function (e) {
|
|
||||||
if (this.skipNextKeyup) {
|
|
||||||
this.skipNextKeyup = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
switch (e.keyCode) {
|
|
||||||
case 40:
|
|
||||||
case 38:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onSelect: function (value) {
|
|
||||||
var pre, post, newSubStr;
|
|
||||||
pre = this.getTextFromHeadToCaret();
|
|
||||||
post = this.el.value.substring(this.el.selectionEnd);
|
|
||||||
|
|
||||||
newSubStr = this.strategy.replace(value);
|
|
||||||
if ($.isArray(newSubStr)) {
|
|
||||||
post = newSubStr[1] + post;
|
|
||||||
newSubStr = newSubStr[0];
|
|
||||||
}
|
|
||||||
pre = pre.replace(this.strategy.match, newSubStr);
|
|
||||||
this.$el.val(pre + post)
|
|
||||||
.trigger('change')
|
|
||||||
.trigger('textComplete:select', value);
|
|
||||||
this.el.focus();
|
|
||||||
this.el.selectionStart = this.el.selectionEnd = pre.length;
|
|
||||||
this.skipNextKeyup = true;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Global click event handler.
|
|
||||||
*/
|
|
||||||
onClickDocument: function (e) {
|
|
||||||
if (e.originalEvent && !e.originalEvent.keepTextCompleteDropdown) {
|
|
||||||
this.listView.deactivate();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Global keyup event handler.
|
|
||||||
*/
|
|
||||||
onKeyupDocument: function (e) {
|
|
||||||
if (this.listView.shown && e.keyCode === 27) { // ESC
|
|
||||||
this.listView.deactivate();
|
|
||||||
this.$el.focus();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove all event handlers and the wrapper element.
|
|
||||||
*/
|
|
||||||
destroy: function () {
|
|
||||||
var $wrapper;
|
|
||||||
this.$el.off('.textComplete');
|
|
||||||
$(document).off('.' + this.id);
|
|
||||||
if (this.listView) { this.listView.destroy(); }
|
|
||||||
$wrapper = this.$el.parent();
|
|
||||||
$wrapper.after(this.$el).remove();
|
|
||||||
this.$el.data('textComplete', void 0);
|
|
||||||
this.$el = null;
|
|
||||||
},
|
|
||||||
|
|
||||||
// Helper methods
|
|
||||||
// ==============
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns caret's relative coordinates from textarea's left top corner.
|
|
||||||
*/
|
|
||||||
getCaretPosition: function () {
|
|
||||||
// Browser native API does not provide the way to know the position of
|
|
||||||
// caret in pixels, so that here we use a kind of hack to accomplish
|
|
||||||
// the aim. First of all it puts a div element and completely copies
|
|
||||||
// the textarea's style to the element, then it inserts the text and a
|
|
||||||
// span element into the textarea.
|
|
||||||
// Consequently, the span element's position is the thing what we want.
|
|
||||||
|
|
||||||
if (this.el.selectionEnd === 0) return;
|
|
||||||
var properties, css, $div, $span, position, dir;
|
|
||||||
|
|
||||||
dir = this.$el.attr('dir') || this.$el.css('direction');
|
|
||||||
properties = ['border-width', 'font-family', 'font-size', 'font-style',
|
|
||||||
'font-variant', 'font-weight', 'height', 'letter-spacing',
|
|
||||||
'word-spacing', 'line-height', 'text-decoration', 'text-align',
|
|
||||||
'width', 'padding-top', 'padding-right', 'padding-bottom',
|
|
||||||
'padding-left', 'margin-top', 'margin-right', 'margin-bottom',
|
|
||||||
'margin-left'
|
|
||||||
];
|
|
||||||
css = $.extend({
|
|
||||||
position: 'absolute',
|
|
||||||
overflow: 'auto',
|
|
||||||
'white-space': 'pre-wrap',
|
|
||||||
top: 0,
|
|
||||||
left: -9999,
|
|
||||||
direction: dir
|
|
||||||
}, getStyles(this.$el, properties));
|
|
||||||
|
|
||||||
$div = $('<div></div>').css(css).text(this.getTextFromHeadToCaret());
|
|
||||||
$span = $('<span></span>').text('.').appendTo($div);
|
|
||||||
this.$el.before($div);
|
|
||||||
position = $span.position();
|
|
||||||
position.top += $span.height() - this.$el.scrollTop();
|
|
||||||
if (dir === 'rtl') { position.left -= this.listView.$el.width(); }
|
|
||||||
$div.remove();
|
|
||||||
return position;
|
|
||||||
},
|
|
||||||
|
|
||||||
getTextFromHeadToCaret: function () {
|
|
||||||
var text, selectionEnd, range;
|
|
||||||
selectionEnd = this.el.selectionEnd;
|
|
||||||
if (typeof selectionEnd === 'number') {
|
|
||||||
text = this.el.value.substring(0, selectionEnd);
|
|
||||||
} else if (document.selection) {
|
|
||||||
range = this.el.createTextRange();
|
|
||||||
range.moveStart('character', 0);
|
|
||||||
range.moveEnd('textedit');
|
|
||||||
text = range.text;
|
|
||||||
}
|
|
||||||
return text;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse the value of textarea and extract search query.
|
|
||||||
*/
|
|
||||||
extractSearchQuery: function (text) {
|
|
||||||
// If a search query found, it returns used strategy and the query
|
|
||||||
// term. If the caret is currently in a code block or search query does
|
|
||||||
// not found, it returns an empty array.
|
|
||||||
|
|
||||||
var i, l, strategy, match;
|
|
||||||
for (i = 0, l = this.strategies.length; i < l; i++) {
|
|
||||||
strategy = this.strategies[i];
|
|
||||||
match = text.match(strategy.match);
|
|
||||||
if (match) { return [strategy, match[strategy.index]]; }
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
},
|
|
||||||
|
|
||||||
search: lock(function (free, searchQuery) {
|
|
||||||
var term;
|
|
||||||
this.strategy = searchQuery[0];
|
|
||||||
term = searchQuery[1];
|
|
||||||
this.strategy.search(term, this.searchCallbackFactory(free));
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Completer's private functions
|
|
||||||
*/
|
|
||||||
var wrapElement = function ($el) {
|
|
||||||
return $el.wrap($baseWrapper.clone().css('display', $el.css('display')));
|
|
||||||
};
|
|
||||||
|
|
||||||
return Completer;
|
|
||||||
})();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dropdown menu manager class.
|
|
||||||
*/
|
|
||||||
var ListView = (function () {
|
|
||||||
|
|
||||||
function ListView($el, completer) {
|
|
||||||
this.data = [];
|
|
||||||
this.$el = $el;
|
|
||||||
this.index = 0;
|
|
||||||
this.completer = completer;
|
|
||||||
|
|
||||||
this.$el.on('click.textComplete', 'li.textcomplete-item',
|
|
||||||
$.proxy(this.onClick, this));
|
|
||||||
}
|
|
||||||
|
|
||||||
$.extend(ListView.prototype, {
|
|
||||||
shown: false,
|
|
||||||
|
|
||||||
render: function (data) {
|
|
||||||
var html, i, l, index, val;
|
|
||||||
|
|
||||||
html = '';
|
|
||||||
for (i = 0, l = data.length; i < l; i++) {
|
|
||||||
val = data[i];
|
|
||||||
if (include(this.data, val)) continue;
|
|
||||||
index = this.data.length;
|
|
||||||
this.data.push(val);
|
|
||||||
html += '<li class="textcomplete-item" data-index="' + index + '"><a>';
|
|
||||||
html += this.strategy.template(val);
|
|
||||||
html += '</a></li>';
|
|
||||||
if (this.data.length === this.strategy.maxCount) break;
|
|
||||||
}
|
|
||||||
this.$el.append(html);
|
|
||||||
if (!this.data.length) {
|
|
||||||
this.deactivate();
|
|
||||||
} else {
|
|
||||||
this.activateIndexedItem();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
clear: function () {
|
|
||||||
this.data = [];
|
|
||||||
this.$el.html('');
|
|
||||||
this.index = 0;
|
|
||||||
return this;
|
|
||||||
},
|
|
||||||
|
|
||||||
activateIndexedItem: function () {
|
|
||||||
this.$el.find('.active').removeClass('active');
|
|
||||||
this.getActiveItem().addClass('active');
|
|
||||||
},
|
|
||||||
|
|
||||||
getActiveItem: function () {
|
|
||||||
return $(this.$el.children().get(this.index));
|
|
||||||
},
|
|
||||||
|
|
||||||
activate: function () {
|
|
||||||
if (!this.shown) {
|
|
||||||
this.$el.show();
|
|
||||||
this.completer.$el.trigger('textComplete:show');
|
|
||||||
this.shown = true;
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
},
|
|
||||||
|
|
||||||
deactivate: function () {
|
|
||||||
if (this.shown) {
|
|
||||||
this.$el.hide();
|
|
||||||
this.completer.$el.trigger('textComplete:hide');
|
|
||||||
this.shown = false;
|
|
||||||
this.data = this.index = null;
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
},
|
|
||||||
|
|
||||||
setPosition: function (position) {
|
|
||||||
this.$el.css(position);
|
|
||||||
return this;
|
|
||||||
},
|
|
||||||
|
|
||||||
select: function (index) {
|
|
||||||
var self = this;
|
|
||||||
this.completer.onSelect(this.data[index]);
|
|
||||||
// Deactive at next tick to allow other event handlers to know whether
|
|
||||||
// the dropdown has been shown or not.
|
|
||||||
setTimeout(function () { self.deactivate(); }, 0);
|
|
||||||
},
|
|
||||||
|
|
||||||
onKeydown: function (e) {
|
|
||||||
if (!this.shown) return;
|
|
||||||
if (e.keyCode === 38) { // UP
|
|
||||||
e.preventDefault();
|
|
||||||
if (this.index === 0) {
|
|
||||||
this.index = this.data.length-1;
|
|
||||||
} else {
|
|
||||||
this.index -= 1;
|
|
||||||
}
|
|
||||||
this.activateIndexedItem();
|
|
||||||
} else if (e.keyCode === 40) { // DOWN
|
|
||||||
e.preventDefault();
|
|
||||||
if (this.index === this.data.length - 1) {
|
|
||||||
this.index = 0;
|
|
||||||
} else {
|
|
||||||
this.index += 1;
|
|
||||||
}
|
|
||||||
this.activateIndexedItem();
|
|
||||||
} else if (e.keyCode === 13 || e.keyCode === 9) { // ENTER or TAB
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
this.select(parseInt(this.getActiveItem().data('index'), 10));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onClick: function (e) {
|
|
||||||
var $e = $(e.target);
|
|
||||||
e.originalEvent.keepTextCompleteDropdown = true;
|
|
||||||
if (!$e.hasClass('textcomplete-item')) {
|
|
||||||
$e = $e.parents('li.textcomplete-item');
|
|
||||||
}
|
|
||||||
this.select(parseInt($e.data('index'), 10));
|
|
||||||
},
|
|
||||||
|
|
||||||
destroy: function () {
|
|
||||||
this.deactivate();
|
|
||||||
this.$el.off('click.textComplete').remove();
|
|
||||||
this.$el = null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return ListView;
|
|
||||||
})();
|
|
||||||
|
|
||||||
$.fn.textcomplete = function (strategies) {
|
|
||||||
var i, l, strategy, dataKey;
|
|
||||||
|
|
||||||
dataKey = 'textComplete';
|
|
||||||
|
|
||||||
if (strategies === 'destroy') {
|
|
||||||
return this.each(function () {
|
|
||||||
var completer = $(this).data(dataKey);
|
|
||||||
if (completer) { completer.destroy(); }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0, l = strategies.length; i < l; i++) {
|
|
||||||
strategy = strategies[i];
|
|
||||||
if (!strategy.template) {
|
|
||||||
strategy.template = identity;
|
|
||||||
}
|
|
||||||
if (strategy.index == null) {
|
|
||||||
strategy.index = 2;
|
|
||||||
}
|
|
||||||
if (strategy.cache) {
|
|
||||||
strategy.search = memoize(strategy.search);
|
|
||||||
}
|
|
||||||
strategy.maxCount || (strategy.maxCount = 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.each(function () {
|
|
||||||
var $this, completer;
|
|
||||||
$this = $(this);
|
|
||||||
completer = $this.data(dataKey);
|
|
||||||
if (!completer) {
|
|
||||||
completer = new Completer($this);
|
|
||||||
$this.data(dataKey, completer);
|
|
||||||
}
|
|
||||||
completer.register(strategies);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
})(window.jQuery || window.Zepto);
|
|
4
js/jquery.textcomplete.min.js
vendored
Normal file
4
js/jquery.textcomplete.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -505,12 +505,14 @@ function filterLang(string) {
|
|||||||
|
|
||||||
// before detection attempts we cut out any mentions and links, and replace _ with space
|
// before detection attempts we cut out any mentions and links, and replace _ with space
|
||||||
langFilterSubj = string.replace(/@\S\w*|https?:\/\/\S*/g, '').replace(/_+/g, ' ')
|
langFilterSubj = string.replace(/@\S\w*|https?:\/\/\S*/g, '').replace(/_+/g, ' ')
|
||||||
|
// cut out common frequently used words FIXME I believe there is a list of similar international stuff somewhere outside which is waiting for us, we should just find it
|
||||||
|
.replace(/\btwister|github|google|twitter\b/g, '')
|
||||||
// replace zero-width word boundaries, such as between letters from different alphabets [or other symbols], with spaces
|
// replace zero-width word boundaries, such as between letters from different alphabets [or other symbols], with spaces
|
||||||
// FIXME not so good idea because 'Za pomocą białej listy' may turn into 'Za pomoc ą bia ł ej listy' for e.g.
|
// FIXME not so good idea because 'Za pomocą białej listy' may turn into 'Za pomoc ą bia ł ej listy' for e.g.
|
||||||
// FIXME but first one was recognized as 'hrv' and second as 'pol' and you know it's 'pol' actually
|
// FIXME but first one was recognized as 'hrv' and second as 'pol' and you know it's 'pol' actually
|
||||||
.replace(/\b/g, ' ')
|
.replace(/\b/g, ' ')
|
||||||
// cut out some more symbols
|
// cut out some more symbols
|
||||||
.replace(/[#\[\]\(\)\{\}\-\+\=\^\:\;\\\/]/g, '')
|
.replace(/[#\[\]\(\)\{\}\-\+\=\^\:\;\\\/0-9]/g, '')
|
||||||
// clear unwanted spaces
|
// clear unwanted spaces
|
||||||
.replace(/\s+/g, ' ').trim();
|
.replace(/\s+/g, ' ').trim();
|
||||||
|
|
||||||
|
@ -2450,62 +2450,45 @@ textarea.splited-post {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Autocomplite*/
|
/*************************************
|
||||||
.textcomplete-wrapper textarea {
|
*********** AUTOCOMPLETING ***********
|
||||||
display: inline;
|
**************************************/
|
||||||
}
|
|
||||||
ul.dropdown-menu {
|
ul.dropdown-menu {
|
||||||
position: absolute;
|
|
||||||
top: 23px;
|
|
||||||
left: 170px;
|
|
||||||
z-index: 100;
|
|
||||||
display: block;
|
|
||||||
float: left;
|
|
||||||
min-width: 160px;
|
min-width: 160px;
|
||||||
|
list-style: none;
|
||||||
padding: 5px 0;
|
padding: 5px 0;
|
||||||
margin: 2px 0 0;
|
margin: 2px 0 0;
|
||||||
list-style: none;
|
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
border: 1px solid rgba(0,0,0, .2);
|
border: 1px solid rgba(0,0,0, .2);
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
-webkit-border-radius: 6px;
|
|
||||||
-moz-border-radius: 6px;
|
|
||||||
-webkit-box-shadow: 0 5px 10px rgba(0,0,0, .2);
|
|
||||||
-moz-box-shadow: 0 5px 10px rgba(0,0,0, .2);
|
|
||||||
box-shadow: 0 5px 10px rgba(0,0,0, .2);
|
box-shadow: 0 5px 10px rgba(0,0,0, .2);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ul.dropdown-menu li {
|
ul.dropdown-menu li {
|
||||||
line-height: 20px;
|
padding: 3px 20px;
|
||||||
|
font: 13px/20px "Open Sans", sans-serif;
|
||||||
|
white-space: nowrap;
|
||||||
|
transition: all 100ms;
|
||||||
}
|
}
|
||||||
ul.dropdown-menu > .active > a {
|
|
||||||
|
ul.dropdown-menu li:hover,
|
||||||
|
ul.dropdown-menu .active, ul.dropdown-menu .active a {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
background-color: #7691ce;
|
background-color: #7691ce;
|
||||||
background-image: linear-gradient(to bottom, #6f88c1, #7e9bdb);
|
background-image: linear-gradient(to bottom, #6f88c1, #7e9bdb);
|
||||||
background-repeat: repeat-x;
|
background-repeat: repeat-x;
|
||||||
|
|
||||||
}
|
|
||||||
ul.dropdown-menu > li > a {
|
|
||||||
display: block;
|
|
||||||
padding: 3px 20px;
|
|
||||||
clear: both;
|
|
||||||
font: 13px/20px "Open Sans", sans-serif;
|
|
||||||
white-space: nowrap;
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
-webkit-transition: all 200ms;
|
|
||||||
-moz-transition: all 200ms;
|
|
||||||
-ms-transition: all 200ms;
|
|
||||||
-o-transition: all 200ms;
|
|
||||||
transition: all 200ms;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ul.dropdown-menu img {
|
ul.dropdown-menu img {
|
||||||
width: 25px;
|
width: 25px;
|
||||||
height: 25px;
|
height: 25px;
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
p.post-text img {
|
p.post-text img {
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
|
@ -3189,45 +3189,32 @@ ol.toptrends-list a:hover {
|
|||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Autocomplite */
|
|
||||||
/* line 1084, ../sass/style.sass */
|
/********** AUTOCOMPLETING *********/
|
||||||
.textcomplete-wrapper textarea {
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* line 1087, ../sass/style.sass */
|
/* line 1087, ../sass/style.sass */
|
||||||
ul.dropdown-menu {
|
ul.dropdown-menu {
|
||||||
position: absolute;
|
|
||||||
top: 23px;
|
|
||||||
left: 155px;
|
|
||||||
z-index: 100;
|
|
||||||
display: block;
|
|
||||||
float: left;
|
|
||||||
min-width: 160px;
|
min-width: 160px;
|
||||||
padding: 5px 0;
|
padding: 5px 0 7px;
|
||||||
margin: 2px 0 0;
|
margin: 2px 0 0;
|
||||||
list-style: none;
|
list-style: none;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
border: 1px solid rgba(0, 0, 0, 0.2);
|
border: 1px solid rgba(0, 0, 0, 0.2);
|
||||||
-webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
|
border-bottom: solid 2px #B4C669;
|
||||||
-moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
|
|
||||||
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
|
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
|
||||||
}
|
}
|
||||||
/* line 1103, ../sass/style.sass */
|
|
||||||
ul.dropdown-menu li {
|
|
||||||
line-height: 20px;
|
|
||||||
}
|
|
||||||
/* line 1105, ../sass/style.sass */
|
/* line 1105, ../sass/style.sass */
|
||||||
ul.dropdown-menu > li > a {
|
ul.dropdown-menu > li > a {
|
||||||
display: block;
|
|
||||||
padding: 3px 20px;
|
padding: 3px 20px;
|
||||||
clear: both;
|
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
-webkit-transition: all 200ms;
|
transition: all 100ms;
|
||||||
-moz-transition: all 200ms;
|
}
|
||||||
-ms-transition: all 200ms;
|
|
||||||
-o-transition: all 200ms;
|
ul.dropdown-menu li:hover,
|
||||||
transition: all 200ms;
|
ul.dropdown-menu .active, ul.dropdown-menu .active a {
|
||||||
|
color: #B4C669;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 1200px) {
|
@media (max-width: 1200px) {
|
||||||
|
@ -1118,39 +1118,25 @@ ol.toptrends-list
|
|||||||
span
|
span
|
||||||
font-style: normal
|
font-style: normal
|
||||||
|
|
||||||
/* Autocomplite*/
|
/********** AUTOCOMPLETING *********/
|
||||||
|
|
||||||
.textcomplete-wrapper textarea
|
.textcomplete-wrapper textarea
|
||||||
display: inline
|
display: inline
|
||||||
|
|
||||||
ul.dropdown-menu
|
ul.dropdown-menu
|
||||||
position: absolute
|
|
||||||
top: 23px
|
|
||||||
left: 155px
|
|
||||||
z-index: 100
|
|
||||||
display: block
|
|
||||||
float: left
|
|
||||||
min-width: 160px
|
min-width: 160px
|
||||||
padding: 5px 0
|
padding: 5px 0 7px
|
||||||
margin: 2px 0 0
|
margin: 2px 0 0
|
||||||
list-style: none
|
list-style: none
|
||||||
background-color: #fff
|
background-color: #fff
|
||||||
border: 1px solid rgba(0, 0, 0, 0.2)
|
border: 1px solid rgba(0, 0, 0, 0.2)
|
||||||
-webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2)
|
border-bottom: solid 2px #B4C669
|
||||||
-moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2)
|
|
||||||
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2)
|
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2)
|
||||||
li
|
li
|
||||||
line-height: 20px
|
|
||||||
> li > a
|
> li > a
|
||||||
display: block
|
|
||||||
padding: 3px 20px
|
padding: 3px 20px
|
||||||
clear: both
|
|
||||||
white-space: nowrap
|
white-space: nowrap
|
||||||
-webkit-transition: all 200ms
|
transition: all 100ms
|
||||||
-moz-transition: all 200ms
|
|
||||||
-ms-transition: all 200ms
|
|
||||||
-o-transition: all 200ms
|
|
||||||
transition: all 200ms
|
|
||||||
|
|
||||||
/* Language filter messages */
|
/* Language filter messages */
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user