diff --git a/view/templates/item/compose-footer.tpl b/view/templates/item/compose-footer.tpl
new file mode 100644
index 0000000000..697be6fd10
--- /dev/null
+++ b/view/templates/item/compose-footer.tpl
@@ -0,0 +1,251 @@
+
diff --git a/view/templates/item/compose.tpl b/view/templates/item/compose.tpl
new file mode 100644
index 0000000000..d18b1a2d36
--- /dev/null
+++ b/view/templates/item/compose.tpl
@@ -0,0 +1,156 @@
+
+
{{$compose_title}}
+
+
+
+
\ No newline at end of file
diff --git a/view/templates/moderated_comment.tpl b/view/templates/moderated_comment.tpl
index d52bf172a0..39dbbde477 100644
--- a/view/templates/moderated_comment.tpl
+++ b/view/templates/moderated_comment.tpl
@@ -6,7 +6,6 @@
-
diff --git a/view/theme/frio/config.php b/view/theme/frio/config.php
index 0f3eda4c94..df0f65a6b8 100644
--- a/view/theme/frio/config.php
+++ b/view/theme/frio/config.php
@@ -16,15 +16,16 @@ function theme_post(App $a)
}
if (isset($_POST['frio-settings-submit'])) {
- PConfig::set(local_user(), 'frio', 'scheme', defaults($_POST, 'frio_scheme', ''));
- PConfig::set(local_user(), 'frio', 'nav_bg', defaults($_POST, 'frio_nav_bg', ''));
- PConfig::set(local_user(), 'frio', 'nav_icon_color', defaults($_POST, 'frio_nav_icon_color', ''));
- PConfig::set(local_user(), 'frio', 'link_color', defaults($_POST, 'frio_link_color', ''));
- PConfig::set(local_user(), 'frio', 'background_color', defaults($_POST, 'frio_background_color', ''));
- PConfig::set(local_user(), 'frio', 'contentbg_transp', defaults($_POST, 'frio_contentbg_transp', ''));
- PConfig::set(local_user(), 'frio', 'background_image', defaults($_POST, 'frio_background_image', ''));
- PConfig::set(local_user(), 'frio', 'bg_image_option', defaults($_POST, 'frio_bg_image_option', ''));
+ PConfig::set(local_user(), 'frio', 'scheme', $_POST['frio_scheme'] ?? '');
+ PConfig::set(local_user(), 'frio', 'nav_bg', $_POST['frio_nav_bg'] ?? '');
+ PConfig::set(local_user(), 'frio', 'nav_icon_color', $_POST['frio_nav_icon_color'] ?? '');
+ PConfig::set(local_user(), 'frio', 'link_color', $_POST['frio_link_color'] ?? '');
+ PConfig::set(local_user(), 'frio', 'background_color', $_POST['frio_background_color'] ?? '');
+ PConfig::set(local_user(), 'frio', 'contentbg_transp', $_POST['frio_contentbg_transp'] ?? '');
+ PConfig::set(local_user(), 'frio', 'background_image', $_POST['frio_background_image'] ?? '');
+ PConfig::set(local_user(), 'frio', 'bg_image_option', $_POST['frio_bg_image_option'] ?? '');
PConfig::set(local_user(), 'frio', 'css_modified', time());
+ PConfig::set(local_user(), 'frio', 'enable_compose', $_POST['frio_enable_compose'] ?? 0);
}
}
@@ -35,17 +36,18 @@ function theme_admin_post(App $a)
}
if (isset($_POST['frio-settings-submit'])) {
- Config::set('frio', 'scheme', defaults($_POST, 'frio_scheme', ''));
- Config::set('frio', 'nav_bg', defaults($_POST, 'frio_nav_bg', ''));
- Config::set('frio', 'nav_icon_color', defaults($_POST, 'frio_nav_icon_color', ''));
- Config::set('frio', 'link_color', defaults($_POST, 'frio_link_color', ''));
- Config::set('frio', 'background_color', defaults($_POST, 'frio_background_color', ''));
- Config::set('frio', 'contentbg_transp', defaults($_POST, 'frio_contentbg_transp', ''));
- Config::set('frio', 'background_image', defaults($_POST, 'frio_background_image', ''));
- Config::set('frio', 'bg_image_option', defaults($_POST, 'frio_bg_image_option', ''));
- Config::set('frio', 'login_bg_image', defaults($_POST, 'frio_login_bg_image', ''));
- Config::set('frio', 'login_bg_color', defaults($_POST, 'frio_login_bg_color', ''));
+ Config::set('frio', 'scheme', $_POST['frio_scheme'] ?? '');
+ Config::set('frio', 'nav_bg', $_POST['frio_nav_bg'] ?? '');
+ Config::set('frio', 'nav_icon_color', $_POST['frio_nav_icon_color'] ?? '');
+ Config::set('frio', 'link_color', $_POST['frio_link_color'] ?? '');
+ Config::set('frio', 'background_color', $_POST['frio_background_color'] ?? '');
+ Config::set('frio', 'contentbg_transp', $_POST['frio_contentbg_transp'] ?? '');
+ Config::set('frio', 'background_image', $_POST['frio_background_image'] ?? '');
+ Config::set('frio', 'bg_image_option', $_POST['frio_bg_image_option'] ?? '');
+ Config::set('frio', 'login_bg_image', $_POST['frio_login_bg_image'] ?? '');
+ Config::set('frio', 'login_bg_color', $_POST['frio_login_bg_color'] ?? '');
Config::set('frio', 'css_modified', time());
+ Config::set('frio', 'enable_compose', $_POST['frio_enable_compose'] ?? 0);
}
}
@@ -67,6 +69,7 @@ function theme_content(App $a)
$arr['contentbg_transp'] = PConfig::get(local_user(), 'frio', 'contentbg_transp', Config::get('frio', 'contentbg_transp'));
$arr['background_image'] = PConfig::get(local_user(), 'frio', 'background_image', Config::get('frio', 'background_image'));
$arr['bg_image_option'] = PConfig::get(local_user(), 'frio', 'bg_image_option' , Config::get('frio', 'bg_image_option'));
+ $arr['enable_compose'] = PConfig::get(local_user(), 'frio', 'enable_compose' , Config::get('frio', 'enable_compose'));
return frio_form($arr);
}
@@ -78,7 +81,7 @@ function theme_admin(App $a)
}
$arr = [];
- $arr['scheme'] = Config::get('frio', 'scheme', Config::get('frio', 'scheme'));
+ $arr['scheme'] = Config::get('frio', 'scheme', Config::get('frio', 'schema'));
$arr['share_string'] = '';
$arr['nav_bg'] = Config::get('frio', 'nav_bg');
$arr['nav_icon_color'] = Config::get('frio', 'nav_icon_color');
@@ -89,6 +92,7 @@ function theme_admin(App $a)
$arr['bg_image_option'] = Config::get('frio', 'bg_image_option');
$arr['login_bg_image'] = Config::get('frio', 'login_bg_image');
$arr['login_bg_color'] = Config::get('frio', 'login_bg_color');
+ $arr['enable_compose'] = Config::get('frio', 'enable_compose');
return frio_form($arr);
}
@@ -132,6 +136,7 @@ function frio_form($arr)
'$background_image' => array_key_exists('background_image', $disable) ? '' : ['frio_background_image', L10n::t('Set the background image'), $arr['background_image'], $background_image_help, false],
'$bg_image_options_title' => L10n::t('Background image style'),
'$bg_image_options' => Image::get_options($arr),
+ '$enable_compose' => ['frio_enable_compose', L10n::t('Enable Compose page'), $arr['enable_compose'], L10n::t('This replaces the jot modal window for writing new posts with a link to the new Compose page.')],
];
if (array_key_exists('login_bg_image', $arr) && !array_key_exists('login_bg_image', $disable)) {
diff --git a/view/theme/frio/css/style.css b/view/theme/frio/css/style.css
index a88276f15d..c986b7232c 100644
--- a/view/theme/frio/css/style.css
+++ b/view/theme/frio/css/style.css
@@ -192,7 +192,6 @@ blockquote {
background-image: none;
text-shadow: none;
border-radius: 3px;
- outline: 0!important;
margin-bottom: 0;
font-size: 14px;
font-weight: 600;
@@ -1314,7 +1313,8 @@ section ul.tabs {
section #jotOpen {
display: none;
}
-#jotOpen {
+#jotOpen,
+#composeOpen {
margin-top: 3px;
float: right;
}
@@ -1372,7 +1372,8 @@ section #jotOpen {
#jot-text-wrap .preview textarea {
width: 100%;
}
-#preview_profile-jot-text {
+#preview_profile-jot-text,
+.comment-edit-form .preview {
position: relative;
padding: 0px 10px;
margin-top: -2px;
@@ -1383,7 +1384,8 @@ section #jotOpen {
background: #fff;
color: #555;
}
-textarea#profile-jot-text:focus + #preview_profile-jot-text {
+textarea#profile-jot-text:focus + #preview_profile-jot-text,
+textarea.comment-edit-text:focus + .comment-edit-form .preview {
border: 2px solid #6fdbe8;
border-top: none;
}
@@ -3425,7 +3427,6 @@ section .profile-match-wrapper {
background-image: none;
text-shadow: none;
border-radius: 3px;
- outline: 0!important;
margin-bottom: 0;
font-size: 14px;
font-weight: 600;
@@ -3444,7 +3445,6 @@ section .profile-match-wrapper {
background-image: none;
text-shadow: none;
border-radius: 3px;
- outline: 0!important;
margin-bottom: 0;
font-size: 14px;
font-weight: 600;
diff --git a/view/theme/frio/frameworks/friendica-tagsinput/LICENSE b/view/theme/frio/frameworks/friendica-tagsinput/LICENSE
new file mode 100644
index 0000000000..58bc985baf
--- /dev/null
+++ b/view/theme/frio/frameworks/friendica-tagsinput/LICENSE
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2013 Tim Schlechter
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/view/theme/frio/frameworks/friendica-tagsinput/friendica-tagsinput-typeahead.css b/view/theme/frio/frameworks/friendica-tagsinput/friendica-tagsinput-typeahead.css
new file mode 100644
index 0000000000..8cec654c47
--- /dev/null
+++ b/view/theme/frio/frameworks/friendica-tagsinput/friendica-tagsinput-typeahead.css
@@ -0,0 +1,54 @@
+/*
+ * friendica-tagsinput v0.8.0
+ *
+ */
+
+.twitter-typeahead .tt-query,
+.twitter-typeahead .tt-hint {
+ margin-bottom: 0;
+}
+
+.twitter-typeahead .tt-hint
+{
+ display: none;
+}
+
+.tt-menu {
+ position: absolute;
+ top: 100%;
+ left: 0;
+ z-index: 1000;
+ display: none;
+ float: left;
+ min-width: 160px;
+ padding: 5px 0;
+ margin: 2px 0 0;
+ list-style: none;
+ font-size: 14px;
+ background-color: #ffffff;
+ border: 1px solid #cccccc;
+ border: 1px solid rgba(0, 0, 0, 0.15);
+ border-radius: 4px;
+ -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
+ box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
+ background-clip: padding-box;
+ cursor: pointer;
+}
+
+.tt-suggestion {
+ display: block;
+ padding: 3px 20px;
+ clear: both;
+ font-weight: normal;
+ line-height: 1.428571429;
+ color: #333333;
+ white-space: nowrap;
+}
+
+.tt-suggestion:hover,
+.tt-suggestion:focus {
+ color: #ffffff;
+ text-decoration: none;
+ outline: 0;
+ background-color: #428bca;
+}
diff --git a/view/theme/frio/frameworks/friendica-tagsinput/friendica-tagsinput.css b/view/theme/frio/frameworks/friendica-tagsinput/friendica-tagsinput.css
new file mode 100644
index 0000000000..f2e1197a55
--- /dev/null
+++ b/view/theme/frio/frameworks/friendica-tagsinput/friendica-tagsinput.css
@@ -0,0 +1,72 @@
+/*
+ * friendica-tagsinput v0.8.0
+ *
+ */
+
+.friendica-tagsinput {
+ background-color: #fff;
+ border: 1px solid #ccc;
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+ display: inline-block;
+ padding: 4px 6px;
+ color: #555;
+ vertical-align: middle;
+ border-radius: 4px;
+ max-width: 100%;
+ line-height: 22px;
+ cursor: text;
+ height: auto;
+}
+.friendica-tagsinput.input-lg {
+ line-height: 27px;
+}
+.friendica-tagsinput input {
+ border: none;
+ box-shadow: none;
+ outline: none;
+ background-color: transparent;
+ padding: 0 6px;
+ margin: 0;
+ width: auto;
+ max-width: inherit;
+}
+.friendica-tagsinput.form-control input::-moz-placeholder {
+ color: #777;
+ opacity: 1;
+}
+.friendica-tagsinput.form-control input:-ms-input-placeholder {
+ color: #777;
+}
+.friendica-tagsinput.form-control input::-webkit-input-placeholder {
+ color: #777;
+}
+.friendica-tagsinput input:focus {
+ border: none;
+ box-shadow: none;
+}
+.friendica-tagsinput .tag {
+ margin: 0 2px 2px 0;
+ color: white;
+ font-weight: normal;
+}
+.friendica-tagsinput .tag img {
+ width: auto;
+ height: 1.5em;
+ vertical-align: text-top;
+ margin-right: 8px;
+}
+.friendica-tagsinput .tag [data-role="remove"] {
+ margin-left: 8px;
+ cursor: pointer;
+}
+.friendica-tagsinput .tag [data-role="remove"]:after {
+ content: "x";
+ padding: 0px 2px;
+ font-weight: bold;
+}
+.friendica-tagsinput .tag [data-role="remove"]:hover {
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+}
+.friendica-tagsinput .tag [data-role="remove"]:hover:active {
+ box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
+}
diff --git a/view/theme/frio/frameworks/friendica-tagsinput/friendica-tagsinput.js b/view/theme/frio/frameworks/friendica-tagsinput/friendica-tagsinput.js
new file mode 100644
index 0000000000..2e83eedc64
--- /dev/null
+++ b/view/theme/frio/frameworks/friendica-tagsinput/friendica-tagsinput.js
@@ -0,0 +1,695 @@
+/*
+ * friendica-tagsinput v0.8.0
+ * Based on bootstrap-tagsinput v0.8.0
+ *
+ * Adds:
+ * - optional thumbnail
+ * - copying source input element class to the pseudo-input element
+ *
+ */
+
+(function ($) {
+ "use strict";
+
+ var defaultOptions = {
+ tagClass: function(item) {
+ return 'label label-info';
+ },
+ focusClass: 'focus',
+ itemValue: function(item) {
+ return item ? item.toString() : item;
+ },
+ itemText: function(item) {
+ return this.itemValue(item);
+ },
+ itemTitle: function(item) {
+ return null;
+ },
+ itemThumb: function(item) {
+ return null;
+ },
+ freeInput: true,
+ addOnBlur: true,
+ maxTags: undefined,
+ maxChars: undefined,
+ confirmKeys: [13, 44],
+ delimiter: ',',
+ delimiterRegex: null,
+ cancelConfirmKeysOnEmpty: false,
+ onTagExists: function(item, $tag) {
+ $tag.hide().fadeIn();
+ },
+ trimValue: false,
+ allowDuplicates: false,
+ triggerChange: true
+ };
+
+ /**
+ * Constructor function
+ */
+ function TagsInput(element, options) {
+ this.isInit = true;
+ this.itemsArray = [];
+
+ this.$element = $(element);
+ this.$element.hide();
+
+ this.isSelect = (element.tagName === 'SELECT');
+ this.multiple = (this.isSelect && element.hasAttribute('multiple'));
+ this.objectItems = options && options.itemValue;
+ this.placeholderText = element.hasAttribute('placeholder') ? this.$element.attr('placeholder') : '';
+ this.inputSize = Math.max(1, this.placeholderText.length);
+
+ this.$container = $('');
+ this.$container.addClass(this.$element.attr('class'));
+ this.$input = $('').appendTo(this.$container);
+
+ this.$element.before(this.$container);
+
+ this.build(options);
+ this.isInit = false;
+ }
+
+ TagsInput.prototype = {
+ constructor: TagsInput,
+
+ /**
+ * Adds the given item as a new tag. Pass true to dontPushVal to prevent
+ * updating the elements val()
+ */
+ add: function(item, dontPushVal, options) {
+ let self = this;
+
+ if (self.options.maxTags && self.itemsArray.length >= self.options.maxTags)
+ return;
+
+ // Ignore falsey values, except false
+ if (item !== false && !item)
+ return;
+
+ // Trim value
+ if (typeof item === "string" && self.options.trimValue) {
+ item = $.trim(item);
+ }
+
+ // Throw an error when trying to add an object while the itemValue option was not set
+ if (typeof item === "object" && !self.objectItems)
+ throw("Can't add objects when itemValue option is not set");
+
+ // Ignore strings only containg whitespace
+ if (item.toString().match(/^\s*$/))
+ return;
+
+ // If SELECT but not multiple, remove current tag
+ if (self.isSelect && !self.multiple && self.itemsArray.length > 0)
+ self.remove(self.itemsArray[0]);
+
+ if (typeof item === "string" && this.$element[0].tagName === 'INPUT') {
+ var delimiter = (self.options.delimiterRegex) ? self.options.delimiterRegex : self.options.delimiter;
+ var items = item.split(delimiter);
+ if (items.length > 1) {
+ for (var i = 0; i < items.length; i++) {
+ this.add(items[i], true);
+ }
+
+ if (!dontPushVal)
+ self.pushVal(self.options.triggerChange);
+ return;
+ }
+ }
+
+ var itemValue = self.options.itemValue(item),
+ itemText = self.options.itemText(item),
+ tagClass = self.options.tagClass(item),
+ itemTitle = self.options.itemTitle(item),
+ itemThumb = self.options.itemThumb(item);
+
+ // Ignore items allready added
+ var existing = $.grep(self.itemsArray, function(item) { return self.options.itemValue(item) === itemValue; } )[0];
+ if (existing && !self.options.allowDuplicates) {
+ // Invoke onTagExists
+ if (self.options.onTagExists) {
+ var $existingTag = $(".tag", self.$container).filter(function() { return $(this).data("item") === existing; });
+ self.options.onTagExists(item, $existingTag);
+ }
+ return;
+ }
+
+ // if length greater than limit
+ if (self.items().toString().length + item.length + 1 > self.options.maxInputLength)
+ return;
+
+ // raise beforeItemAdd arg
+ var beforeItemAddEvent = $.Event('beforeItemAdd', { item: item, cancel: false, options: options});
+ self.$element.trigger(beforeItemAddEvent);
+ if (beforeItemAddEvent.cancel)
+ return;
+
+ // register item in internal array and map
+ self.itemsArray.push(item);
+
+ // add a tag element
+ var $tag = $('' +
+ (itemThumb !== null ? '' : '') +
+ htmlEncode(itemText) + '' +
+ '');
+ $tag.data('item', item);
+ self.findInputWrapper().before($tag);
+ $tag.after(' ');
+
+ // Check to see if the tag exists in its raw or uri-encoded form
+ var optionExists = (
+ $('option[value="' + encodeURIComponent(itemValue) + '"]', self.$element).length ||
+ $('option[value="' + htmlEncode(itemValue) + '"]', self.$element).length
+ );
+
+ // add if item represents a value not present in one of the 's options
+ if (self.isSelect && !optionExists) {
+ var $option = $('');
+ $option.data('item', item);
+ $option.attr('value', itemValue);
+ self.$element.append($option);
+ }
+
+ if (!dontPushVal)
+ self.pushVal(self.options.triggerChange);
+
+ // Add class when reached maxTags
+ if (self.options.maxTags === self.itemsArray.length || self.items().toString().length === self.options.maxInputLength)
+ self.$container.addClass('friendica-tagsinput-max');
+
+ // If using typeahead, once the tag has been added, clear the typeahead value so it does not stick around in the input.
+ if ($('.typeahead, .twitter-typeahead', self.$container).length) {
+ self.$input.typeahead('val', '');
+ }
+
+ if (this.isInit) {
+ self.$element.trigger($.Event('itemAddedOnInit', { item: item, options: options }));
+ } else {
+ self.$element.trigger($.Event('itemAdded', { item: item, options: options }));
+ }
+ },
+
+ /**
+ * Removes the given item. Pass true to dontPushVal to prevent updating the
+ * elements val()
+ */
+ remove: function(item, dontPushVal, options) {
+ var self = this;
+
+ if (self.objectItems) {
+ if (typeof item === "object")
+ item = $.grep(self.itemsArray, function(other) { return self.options.itemValue(other) == self.options.itemValue(item); } );
+ else
+ item = $.grep(self.itemsArray, function(other) { return self.options.itemValue(other) == item; } );
+
+ item = item[item.length-1];
+ }
+
+ if (item) {
+ var beforeItemRemoveEvent = $.Event('beforeItemRemove', { item: item, cancel: false, options: options });
+ self.$element.trigger(beforeItemRemoveEvent);
+ if (beforeItemRemoveEvent.cancel)
+ return;
+
+ $('.tag', self.$container).filter(function() { return $(this).data('item') === item; }).remove();
+ $('option', self.$element).filter(function() { return $(this).data('item') === item; }).remove();
+ if($.inArray(item, self.itemsArray) !== -1)
+ self.itemsArray.splice($.inArray(item, self.itemsArray), 1);
+ }
+
+ if (!dontPushVal)
+ self.pushVal(self.options.triggerChange);
+
+ // Remove class when reached maxTags
+ if (self.options.maxTags > self.itemsArray.length)
+ self.$container.removeClass('friendica-tagsinput-max');
+
+ self.$element.trigger($.Event('itemRemoved', { item: item, options: options }));
+ },
+
+ /**
+ * Removes all items
+ */
+ removeAll: function() {
+ var self = this;
+
+ $('.tag', self.$container).remove();
+ $('option', self.$element).remove();
+
+ while(self.itemsArray.length > 0)
+ self.itemsArray.pop();
+
+ self.pushVal(self.options.triggerChange);
+ },
+
+ /**
+ * Refreshes the tags so they match the text/value of their corresponding
+ * item.
+ */
+ refresh: function() {
+ var self = this;
+ $('.tag', self.$container).each(function() {
+ var $tag = $(this),
+ item = $tag.data('item'),
+ itemValue = self.options.itemValue(item),
+ itemText = self.options.itemText(item),
+ tagClass = self.options.tagClass(item);
+
+ // Update tag's class and inner text
+ $tag.attr('class', null);
+ $tag.addClass('tag ' + htmlEncode(tagClass));
+ $tag.contents().filter(function() {
+ return this.nodeType == 3;
+ })[0].nodeValue = htmlEncode(itemText);
+
+ if (self.isSelect) {
+ var option = $('option', self.$element).filter(function() { return $(this).data('item') === item; });
+ option.attr('value', itemValue);
+ }
+ });
+ },
+
+ /**
+ * Returns the items added as tags
+ */
+ items: function() {
+ return this.itemsArray;
+ },
+
+ /**
+ * Assembly value by retrieving the value of each item, and set it on the
+ * element.
+ */
+ pushVal: function() {
+ var self = this,
+ val = $.map(self.items(), function(item) {
+ return self.options.itemValue(item).toString();
+ });
+
+ self.$element.val(val, true);
+
+ if (self.options.triggerChange)
+ self.$element.trigger('change');
+ },
+
+ /**
+ * Initializes the tags input behaviour on the element
+ */
+ build: function(options) {
+ var self = this;
+
+ self.options = $.extend({}, defaultOptions, options);
+ // When itemValue is set, freeInput should always be false
+ if (self.objectItems)
+ self.options.freeInput = false;
+
+ makeOptionItemFunction(self.options, 'itemValue');
+ makeOptionItemFunction(self.options, 'itemText');
+ makeOptionItemFunction(self.options, 'itemThumb');
+ makeOptionFunction(self.options, 'tagClass');
+
+ // Typeahead Bootstrap version 2.3.2
+ if (self.options.typeahead) {
+ var typeahead = self.options.typeahead || {};
+
+ makeOptionFunction(typeahead, 'source');
+
+ self.$input.typeahead($.extend({}, typeahead, {
+ source: function (query, process) {
+ function processItems(items) {
+ var texts = [];
+
+ for (var i = 0; i < items.length; i++) {
+ var text = self.options.itemText(items[i]);
+ map[text] = items[i];
+ texts.push(text);
+ }
+ process(texts);
+ }
+
+ this.map = {};
+ var map = this.map,
+ data = typeahead.source(query);
+
+ if ($.isFunction(data.success)) {
+ // support for Angular callbacks
+ data.success(processItems);
+ } else if ($.isFunction(data.then)) {
+ // support for Angular promises
+ data.then(processItems);
+ } else {
+ // support for functions and jquery promises
+ $.when(data)
+ .then(processItems);
+ }
+ },
+ updater: function (text) {
+ self.add(this.map[text]);
+ return this.map[text];
+ },
+ matcher: function (text) {
+ return (text.toLowerCase().indexOf(this.query.trim().toLowerCase()) !== -1);
+ },
+ sorter: function (texts) {
+ return texts.sort();
+ },
+ highlighter: function (text) {
+ var regex = new RegExp( '(' + this.query + ')', 'gi' );
+ return text.replace( regex, "$1" );
+ }
+ }));
+ }
+
+ // typeahead.js
+ if (self.options.typeaheadjs) {
+ var typeaheadConfig = null;
+ var typeaheadDatasets = {};
+
+ // Determine if main configurations were passed or simply a dataset
+ var typeaheadjs = self.options.typeaheadjs;
+ if ($.isArray(typeaheadjs)) {
+ typeaheadConfig = typeaheadjs[0];
+ typeaheadDatasets = typeaheadjs[1];
+ } else {
+ typeaheadDatasets = typeaheadjs;
+ }
+
+ self.$input.typeahead(typeaheadConfig, typeaheadDatasets).on('typeahead:selected', $.proxy(function (obj, datum) {
+ if (typeaheadDatasets.valueKey)
+ self.add(datum[typeaheadDatasets.valueKey]);
+ else
+ self.add(datum);
+ self.$input.typeahead('val', '');
+ }, self));
+ }
+
+ self.$container.on('click', $.proxy(function(event) {
+ if (! self.$element.attr('disabled')) {
+ self.$input.removeAttr('disabled');
+ }
+ self.$input.focus();
+ }, self));
+
+ if (self.options.addOnBlur && self.options.freeInput) {
+ self.$input.on('focusout', $.proxy(function(event) {
+ // HACK: only process on focusout when no typeahead opened, to
+ // avoid adding the typeahead text as tag
+ if ($('.typeahead, .twitter-typeahead', self.$container).length === 0) {
+ self.add(self.$input.val());
+ self.$input.val('');
+ }
+ }, self));
+ }
+
+ // Toggle the 'focus' css class on the container when it has focus
+ self.$container.on({
+ focusin: function() {
+ self.$container.addClass(self.options.focusClass);
+ },
+ focusout: function() {
+ self.$container.removeClass(self.options.focusClass);
+ },
+ });
+
+ self.$container.on('keydown', 'input', $.proxy(function(event) {
+ var $input = $(event.target),
+ $inputWrapper = self.findInputWrapper();
+
+ if (self.$element.attr('disabled')) {
+ self.$input.attr('disabled', 'disabled');
+ return;
+ }
+
+ switch (event.which) {
+ // BACKSPACE
+ case 8:
+ if (doGetCaretPosition($input[0]) === 0) {
+ var prev = $inputWrapper.prev();
+ if (prev.length) {
+ self.remove(prev.data('item'));
+ }
+ }
+ break;
+
+ // DELETE
+ case 46:
+ if (doGetCaretPosition($input[0]) === 0) {
+ var next = $inputWrapper.next();
+ if (next.length) {
+ self.remove(next.data('item'));
+ }
+ }
+ break;
+
+ // LEFT ARROW
+ case 37:
+ // Try to move the input before the previous tag
+ var $prevTag = $inputWrapper.prev();
+ if ($input.val().length === 0 && $prevTag[0]) {
+ $prevTag.before($inputWrapper);
+ $input.focus();
+ }
+ break;
+ // RIGHT ARROW
+ case 39:
+ // Try to move the input after the next tag
+ var $nextTag = $inputWrapper.next();
+ if ($input.val().length === 0 && $nextTag[0]) {
+ $nextTag.after($inputWrapper);
+ $input.focus();
+ }
+ break;
+ default:
+ // ignore
+ }
+
+ // Reset internal input's size
+ var textLength = $input.val().length,
+ wordSpace = Math.ceil(textLength / 5),
+ size = textLength + wordSpace + 1;
+ $input.attr('size', Math.max(this.inputSize, $input.val().length));
+ }, self));
+
+ self.$container.on('keypress', 'input', $.proxy(function(event) {
+ var $input = $(event.target);
+
+ if (self.$element.attr('disabled')) {
+ self.$input.attr('disabled', 'disabled');
+ return;
+ }
+
+ var text = $input.val(),
+ maxLengthReached = self.options.maxChars && text.length >= self.options.maxChars;
+ if (self.options.freeInput && (keyCombinationInList(event, self.options.confirmKeys) || maxLengthReached)) {
+ // Only attempt to add a tag if there is data in the field
+ if (text.length !== 0) {
+ self.add(maxLengthReached ? text.substr(0, self.options.maxChars) : text);
+ $input.val('');
+ }
+
+ // If the field is empty, let the event triggered fire as usual
+ if (self.options.cancelConfirmKeysOnEmpty === false) {
+ event.preventDefault();
+ }
+ }
+
+ // Reset internal input's size
+ var textLength = $input.val().length,
+ wordSpace = Math.ceil(textLength / 5),
+ size = textLength + wordSpace + 1;
+ $input.attr('size', Math.max(this.inputSize, $input.val().length));
+ }, self));
+
+ // Remove icon clicked
+ self.$container.on('click', '[data-role=remove]', $.proxy(function(event) {
+ if (self.$element.attr('disabled')) {
+ return;
+ }
+ self.remove($(event.target).closest('.tag').data('item'));
+ }, self));
+
+ // Only add existing value as tags when using strings as tags
+ if (self.options.itemValue === defaultOptions.itemValue) {
+ if (self.$element[0].tagName === 'INPUT') {
+ self.add(self.$element.val());
+ } else {
+ $('option', self.$element).each(function() {
+ self.add($(this).attr('value'), true);
+ });
+ }
+ }
+ },
+
+ /**
+ * Removes all tagsinput behaviour and unregsiter all event handlers
+ */
+ destroy: function() {
+ var self = this;
+
+ // Unbind events
+ self.$container.off('keypress', 'input');
+ self.$container.off('click', '[role=remove]');
+
+ self.$container.remove();
+ self.$element.removeData('tagsinput');
+ self.$element.show();
+ },
+
+ /**
+ * Sets focus on the tagsinput
+ */
+ focus: function() {
+ this.$input.focus();
+ },
+
+ /**
+ * Returns the internal input element
+ */
+ input: function() {
+ return this.$input;
+ },
+
+ /**
+ * Returns the element which is wrapped around the internal input. This
+ * is normally the $container, but typeahead.js moves the $input element.
+ */
+ findInputWrapper: function() {
+ var elt = this.$input[0],
+ container = this.$container[0];
+ while(elt && elt.parentNode !== container)
+ elt = elt.parentNode;
+
+ return $(elt);
+ }
+ };
+
+ /**
+ * Register JQuery plugin
+ */
+ $.fn.tagsinput = function(arg1, arg2, arg3) {
+ var results = [];
+
+ this.each(function() {
+ var tagsinput = $(this).data('tagsinput');
+ // Initialize a new tags input
+ if (!tagsinput) {
+ tagsinput = new TagsInput(this, arg1);
+ $(this).data('tagsinput', tagsinput);
+ results.push(tagsinput);
+
+ if (this.tagName === 'SELECT') {
+ $('option', $(this)).attr('selected', 'selected');
+ }
+
+ // Init tags from $(this).val()
+ $(this).val($(this).val());
+ } else if (!arg1 && !arg2) {
+ // tagsinput already exists
+ // no function, trying to init
+ results.push(tagsinput);
+ } else if(tagsinput[arg1] !== undefined) {
+ // Invoke function on existing tags input
+ if(tagsinput[arg1].length === 3 && arg3 !== undefined){
+ var retVal = tagsinput[arg1](arg2, null, arg3);
+ }else{
+ var retVal = tagsinput[arg1](arg2);
+ }
+ if (retVal !== undefined)
+ results.push(retVal);
+ }
+ });
+
+ if ( typeof arg1 == 'string') {
+ // Return the results from the invoked function calls
+ return results.length > 1 ? results : results[0];
+ } else {
+ return results;
+ }
+ };
+
+ $.fn.tagsinput.Constructor = TagsInput;
+
+ /**
+ * Most options support both a string or number as well as a function as
+ * option value. This function makes sure that the option with the given
+ * key in the given options is wrapped in a function
+ */
+ function makeOptionItemFunction(options, key) {
+ if (typeof options[key] !== 'function') {
+ var propertyName = options[key];
+ options[key] = function(item) { return item[propertyName]; };
+ }
+ }
+ function makeOptionFunction(options, key) {
+ if (typeof options[key] !== 'function') {
+ var value = options[key];
+ options[key] = function() { return value; };
+ }
+ }
+ /**
+ * HtmlEncodes the given value
+ */
+ var htmlEncodeContainer = $('');
+ function htmlEncode(value) {
+ if (value) {
+ return htmlEncodeContainer.text(value).html();
+ } else {
+ return '';
+ }
+ }
+
+ /**
+ * Returns the position of the caret in the given input field
+ * http://flightschool.acylt.com/devnotes/caret-position-woes/
+ */
+ function doGetCaretPosition(oField) {
+ var iCaretPos = 0;
+ if (document.selection) {
+ oField.focus ();
+ var oSel = document.selection.createRange();
+ oSel.moveStart ('character', -oField.value.length);
+ iCaretPos = oSel.text.length;
+ } else if (oField.selectionStart || oField.selectionStart == '0') {
+ iCaretPos = oField.selectionStart;
+ }
+ return (iCaretPos);
+ }
+
+ /**
+ * Returns boolean indicates whether user has pressed an expected key combination.
+ * @param object keyPressEvent: JavaScript event object, refer
+ * http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
+ * @param object lookupList: expected key combinations, as in:
+ * [13, {which: 188, shiftKey: true}]
+ */
+ function keyCombinationInList(keyPressEvent, lookupList) {
+ var found = false;
+ $.each(lookupList, function (index, keyCombination) {
+ if (typeof (keyCombination) === 'number' && keyPressEvent.which === keyCombination) {
+ found = true;
+ return false;
+ }
+
+ if (keyPressEvent.which === keyCombination.which) {
+ var alt = !keyCombination.hasOwnProperty('altKey') || keyPressEvent.altKey === keyCombination.altKey,
+ shift = !keyCombination.hasOwnProperty('shiftKey') || keyPressEvent.shiftKey === keyCombination.shiftKey,
+ ctrl = !keyCombination.hasOwnProperty('ctrlKey') || keyPressEvent.ctrlKey === keyCombination.ctrlKey;
+ if (alt && shift && ctrl) {
+ found = true;
+ return false;
+ }
+ }
+ });
+
+ return found;
+ }
+
+ /**
+ * Initialize tagsinput behaviour on inputs and selects which have
+ * data-role=tagsinput
+ */
+ $(function() {
+ $("input[data-role=tagsinput], select[multiple][data-role=tagsinput]").tagsinput();
+ });
+})(window.jQuery);
diff --git a/view/theme/frio/js/theme.js b/view/theme/frio/js/theme.js
index 19b5c4fa6e..44a24b30a1 100644
--- a/view/theme/frio/js/theme.js
+++ b/view/theme/frio/js/theme.js
@@ -64,9 +64,24 @@ $(document).ready(function(){
});
// add Jot botton to the scecond navbar
- if( $("section #jotOpen").length ) {
- $("section #jotOpen").appendTo("#topbar-second > .container > #navbar-button");
- if( $("#jot-popup").is(":hidden")) $("#topbar-second > .container > #navbar-button #jotOpen").hide();
+ let $jotButton = $("#jotOpen");
+ let $composeButton = $("#composeOpen");
+ if (compose) {
+ $jotButton.hide();
+ if ($composeButton.length) {
+ $composeButton.appendTo("#topbar-second > .container > #navbar-button");
+ if($("#jot-popup").is(":hidden")) {
+ $composeButton.hide();
+ }
+ }
+ } else {
+ $composeButton.hide();
+ if ($jotButton.length) {
+ $jotButton.appendTo("#topbar-second > .container > #navbar-button");
+ if($("#jot-popup").is(":hidden")) {
+ $jotButton.hide();
+ }
+ }
}
// show bulk deletion button at network page if checkbox is checked
diff --git a/view/theme/frio/templates/comment_item.tpl b/view/theme/frio/templates/comment_item.tpl
index 98b3c45636..b60f5c429e 100644
--- a/view/theme/frio/templates/comment_item.tpl
+++ b/view/theme/frio/templates/comment_item.tpl
@@ -10,7 +10,6 @@
{{**}}
-
diff --git a/view/theme/frio/templates/jot.tpl b/view/theme/frio/templates/jot.tpl
index d5ba1bcc45..8b103eba56 100644
--- a/view/theme/frio/templates/jot.tpl
+++ b/view/theme/frio/templates/jot.tpl
@@ -1,6 +1,6 @@
{{* The button to open the jot - in This theme we move the button with js to the second nav bar *}}
-
+
{{$compose_title}}
+diff --git a/view/theme/frio/templates/jot.tpl b/view/theme/frio/templates/jot.tpl index d5ba1bcc45..8b103eba56 100644 --- a/view/theme/frio/templates/jot.tpl +++ b/view/theme/frio/templates/jot.tpl @@ -1,6 +1,6 @@ {{* The button to open the jot - in This theme we move the button with js to the second nav bar *}} - +