Skip to content

Commit

Permalink
v0.1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
sk-ys committed Aug 5, 2023
1 parent 8fb172a commit 3b37189
Show file tree
Hide file tree
Showing 9 changed files with 267 additions and 1 deletion.
17 changes: 17 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# EditorConfig is awesome: https://EditorConfig.org

# top-most EditorConfig file
root = true

# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 2
charset = utf-8

[*.{md,markdown}]
trim_trailing_whitespace = false
indent_size = 4
6 changes: 6 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"cSpell.words": [
"jstb",
"Jstoolbar"
]
}
35 changes: 34 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,34 @@
# redmine_jstoolbar_slider
# Redmine jsToolBar Slider

This is a plugin for Redmine.
This plugin adds two buttons to the right edge of the jsToolBar that allow
sliding the toolbar buttons when the toolbar is overflowing.

## Demo

![](/doc/images/jsToolbar_slider_demo.gif)

## Compatibility

Only Redmine v5.0.5 has been tested.
Other versions are untested.

## Installation

### When using git

1. Change the current directory to the Redmine plugin directory.
```
cd YOUR_REDMINE_DIRECTORY/plugins
```
2. Clone this repository.
```
git clone https://github.com/sk-ys/redmine_jstoolbar_slider.git
```
3. Restart Redmine.

### When not using git

1. Download zip file from the [release page](https://github.com/sk-ys/redmine_jstoolbar_slider/releases) or the [latest main repository](https://github.com/sk-ys/redmine_jstoolbar_slider/archive/refs/heads/main.zip).
2. Extract the ZIP file to your Redmine plugin directory. The name of the unzipped directory must be `redmine_jstoolbar_slider`.
3. Restart Redmine.
14 changes: 14 additions & 0 deletions app/views/jstoolbar_slider/_base.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<% content_for :header_tags do %>
<script>
var JstoolbarSlider = {
config: {
resources: {
labelUndo: "<%= l(:jstoolbar_slider_label_undo) %>",
labelRedo: "<%= l(:jstoolbar_slider_label_redo) %>",
}
}
}
</script>
<%= javascript_include_tag "jstoolbar_slider", plugin: "redmine_jstoolbar_slider" %>
<%= stylesheet_link_tag "jstoolbar_slider", plugin: "redmine_jstoolbar_slider" %>
<% end %>
141 changes: 141 additions & 0 deletions assets/javascripts/jstoolbar_slider.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
(() => {
if (typeof jsToolBar === "undefined") return;

function shiftTabElements(
sliderButton,
direction,
continuous = false,
complete = null
) {
const $tabElements = $(sliderButton)
.closest("div.jstTabs")
.find("ul > li.tab-elements")
.eq(0);

// Calculate the amount of shift
const shift = continuous ? 50 : $tabElements.width() / 2;

// Shift
$tabElements.animate(
{
scrollLeft:
$tabElements.scrollLeft() + shift * (direction === "left" ? -1 : 1),
},
{
easing: continuous ? "linear" : "swing",
queue: false,
start: () => {
if (continuous) {
$(sliderButton).addClass("continuous");
} else {
$(sliderButton).removeClass("continuous");
}
},
complete: () => {
setTimeout(() => {
if (
continuous &&
$(sliderButton).hasClass("continuous") &&
$(sliderButton).is(":hover") &&
(direction === "left"
? $tabElements.scrollLeft() > 0
: Math.ceil($tabElements.scrollLeft() + $tabElements.width()) <
$tabElements[0].scrollWidth)
) {
shiftTabElements(sliderButton, direction, continuous, complete);
} else {
$(sliderButton).removeClass("continuous");
}
});
if (typeof complete === "function") complete();
},
}
);
}

function changeSliderButtonsVisibility(sliderButtons) {
const $sliderButtons = $(sliderButtons);
const tabElements = $sliderButtons.closest("ul").find("li.tab-elements")[0];

function isOverFlow() {
return (
tabElements.offsetWidth <
tabElements.scrollWidth - $sliderButtons.parent().width()
);
}

$sliderButtons
.toggle(isOverFlow())
.toggleClass("at-the-left", $(tabElements).scrollLeft() === 0)
.toggleClass(
"at-the-right",
Math.ceil($(tabElements).scrollLeft() + $(tabElements).width()) >=
tabElements.scrollWidth
);
}

function addSliderButtonsToJstoolbar(tabsBlock) {
const $tabsBlock = $(tabsBlock);
if ($tabsBlock.find(".slider-buttons").length > 0) return;

let shiftEventId = null;
const mouseOverActionDelay = 1000;

function generateButton(direction) {
return $("<button/>")
.attr("type", "button")
.addClass(`icon shift-${direction}`)
.on("click", (e) => {
clearTimeout(shiftEventId);
shiftTabElements(e.target, direction, false, () => {
changeSliderButtonsVisibility($sliderButtons);
});
})
.on("mouseover", (e) => {
clearTimeout(shiftEventId);
shiftEventId = setTimeout(() => {
shiftTabElements(e.target, direction, true, () => {
changeSliderButtonsVisibility($sliderButtons);
});
}, mouseOverActionDelay);
})
.on("mouseout", () => {
clearTimeout(shiftEventId);
});
}

// Generate slider buttons
const $sliderButtons = $("<div/>")
.addClass("slider-buttons")
.addClass("jstElements")
.append(generateButton("left"))
.append(generateButton("right"));

// Append slider buttons to jsToolBar
$tabsBlock.children("ul").append($("<li/>").append($sliderButtons));

// Dynamically control the visibility of slider using ResizeObserver
new ResizeObserver(() => {
const $sliderButtons = $tabsBlock.find(".slider-buttons");
changeSliderButtonsVisibility($sliderButtons);
}).observe($tabsBlock.find("li.tab-elements")[0]);

// Initial application
setTimeout(changeSliderButtonsVisibility($sliderButtons));
}

// Trigger to initialize the jsToolBar Slider
const initJstoolbarSlider = {
type: "init_jstoolbar_slider",
};

// Add to toolbar
jsToolBar.prototype.elements = {
...jsToolBar.prototype.elements,
init_jstoolbar_slider: initJstoolbarSlider,
};

jsToolBar.prototype.init_jstoolbar_slider = function () {
addSliderButtonsToJstoolbar(this.tabsBlock);
};
})();
42 changes: 42 additions & 0 deletions assets/stylesheets/jstoolbar_slider.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
@media screen and (max-width: 899px) {
#content .jstTabs {
width: 100%;
}
}
#content .jstTabs.tabs ul {
min-width: unset;
display: flex;
flex-direction: row;
width: 99%;
}
#content .jstTabs.tabs ul > li {
flex: 0 0 auto;
}
#content .jstTabs.tabs ul > li.tab-elements {
flex: 1 1 auto;
overflow: hidden;
}
#content .jstTabs.tabs .slider-buttons {
padding-right: 0;
padding-left: 0;
}
#content .jstTabs.tabs .slider-buttons button {
position: static;
}
div.jstElements button.shift-left,
div.jstElements button.shift-right {
right: 28px;
border-top-left-radius: 3px;
background-color: #eee;
}
div.jstElements button.shift-left {
background: url(../../../images/arrow_left.png) no-repeat 50% 50% !important;
}
div.jstElements button.shift-right {
background: url(../../../images/arrow_right.png) no-repeat 50% 50% !important;
}
div.jstElements.slider-buttons.at-the-left button.shift-left,
div.jstElements.slider-buttons.at-the-right button.shift-right {
background-color: #ccc !important;
opacity: 1;
}
Binary file added doc/images/jsToolbar_slider_demo.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions init.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
require_dependency File.expand_path("../lib/jstoolbar_slider/hooks.rb", __FILE__)

Redmine::Plugin.register :redmine_jstoolbar_slider do
name "Redmine jsToolbar Slider plugin"
author "sk-ys"
description "This is a plugin for Redmine"
version "0.1.0"
url "https://github.com/sk-ys/redmine_jstoolbar_slider"
author_url "https://github.com/sk-ys"
end
3 changes: 3 additions & 0 deletions lib/jstoolbar_slider/hooks.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class JstoolbarSlider::Hooks < Redmine::Hook::ViewListener
render_on :view_layouts_base_html_head, :partial => "jstoolbar_slider/base"
end

0 comments on commit 3b37189

Please sign in to comment.