From a2b6251677f4f21244fa08b3350f9714c51bc4a2 Mon Sep 17 00:00:00 2001 From: Sean Date: Fri, 27 Jul 2018 09:54:19 +0100 Subject: [PATCH 1/5] Added shields --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index ad341a9f96..8e0b052a11 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,12 @@ # Fomantic UI + +[![Discord](https://img.shields.io/discord/453127116427493376.svg?label=Discord)](https://discord.gg/YChxjJ3) +[![npm downloads](https://img.shields.io/npm/dw/fomantic-ui.svg)](https://www.npmjs.com/package/fomantic-ui) +[![npm version](https://img.shields.io/npm/v/fomantic-ui.svg)](https://www.npmjs.com/package/fomantic-ui) +[![last commit](https://img.shields.io/github/last-commit/hammy2899/fomantic-ui.svg)](https://github.com/hammy2899/Fomantic-UI/commits/master) + [Fomantic](http://fomantic-ui.com) is a community fork of the popular Semantic-UI framework. *NOTE:* Fomantic was created to continue active development of Semantic-UI and has the intent to be merged back into the master repository once active development can restart. For more info please read the following issues https://github.com/Semantic-Org/Semantic-UI/issues/6109 https://github.com/Semantic-Org/Semantic-UI/issues/6413 From c04e273658033205d49b97c231ed912eeae04f1d Mon Sep 17 00:00:00 2001 From: Sean Hamilton Date: Sat, 28 Jul 2018 02:24:17 +0100 Subject: [PATCH 2/5] Added range component --- src/definitions/globals/site.js | 5 +- src/definitions/modules/range.js | 273 +++++++++++++++++++++ src/definitions/modules/range.less | 207 ++++++++++++++++ src/semantic.less | 1 + src/themes/default/modules/range.overrides | 3 + src/themes/default/modules/range.variables | 30 +++ tasks/config/admin/release.js | 1 + tasks/config/defaults.js | 1 + tasks/config/project/install.js | 1 + 9 files changed, 520 insertions(+), 2 deletions(-) create mode 100644 src/definitions/modules/range.js create mode 100644 src/definitions/modules/range.less create mode 100644 src/themes/default/modules/range.overrides create mode 100644 src/themes/default/modules/range.variables diff --git a/src/definitions/globals/site.js b/src/definitions/globals/site.js index 63cbd9dbfd..0b79d08d93 100644 --- a/src/definitions/globals/site.js +++ b/src/definitions/globals/site.js @@ -447,6 +447,7 @@ $.site.settings = { 'modal', 'nag', 'popup', + 'range', 'rating', 'shape', 'sidebar', @@ -454,8 +455,8 @@ $.site.settings = { 'sticky', 'tab', 'transition', - 'visit', - 'visibility' + 'visibility', + 'visit' ], siteNamespace : 'site', diff --git a/src/definitions/modules/range.js b/src/definitions/modules/range.js new file mode 100644 index 0000000000..50956e7324 --- /dev/null +++ b/src/definitions/modules/range.js @@ -0,0 +1,273 @@ +/*! + * # Range slider for Semantic UI. + * + */ + +;(function ( $, window, document, undefined ) { + + "use strict"; + + $.fn.range = function(parameters) { + + var + $allModules = $(this), + + offset = 10, + + query = arguments[0], + methodInvoked = (typeof query == 'string'), + queryArguments = [].slice.call(arguments, 1) + ; + + $allModules + .each(function() { + + var + settings = ( $.isPlainObject(parameters) ) + ? $.extend(true, {}, $.fn.range.settings, parameters) + : $.extend({}, $.fn.range.settings), + + namespace = settings.namespace, + min = settings.min, + max = settings.max, + step = settings.step, + start = settings.start, + input = settings.input, + + eventNamespace = '.' + namespace, + moduleNamespace = 'module-' + namespace, + + $module = $(this), + + element = this, + instance = $module.data(moduleNamespace), + + inner, + thumb, + trackLeft, + precision, + + module + ; + + module = { + + initialize: function() { + module.instantiate(); + module.sanitize(); + }, + + instantiate: function() { + instance = module; + $module + .data(moduleNamespace, module) + ; + $(element).html("
"); + inner = $(element).children('.inner')[0]; + thumb = $(element).find('.thumb')[0]; + trackLeft = $(element).find('.track-fill')[0]; + // find precision of step, used in calculating the value + module.determinePrecision(); + // set start location + module.setValuePosition(settings.start); + // event listeners + $(element).find('.track, .thumb, .inner').on('mousedown', function(event) { + event.stopImmediatePropagation(); + event.preventDefault(); + $(this).closest(".range").trigger('mousedown', event); + }); + $(element).find('.track, .thumb, .inner').on('touchstart', function(event) { + event.stopImmediatePropagation(); + event.preventDefault(); + $(this).closest(".range").trigger('touchstart', event); + }); + $(element).on('mousedown', function(event, originalEvent) { + module.rangeMousedown(event, false, originalEvent); + }); + $(element).on('touchstart', function(event, originalEvent) { + module.rangeMousedown(event, true, originalEvent); + }); + module.addVisibilityListener(element); + }, + + sanitize: function() { + if (typeof settings.min != 'number') { + settings.min = parseInt(settings.min) || 0; + } + if (typeof settings.max != 'number') { + settings.max = parseInt(settings.max) || false; + } + if (typeof settings.start != 'number') { + settings.start = parseInt(settings.start) || 0; + } + }, + + determinePrecision: function() { + var split = String(settings.step).split('.'); + var decimalPlaces; + if(split.length == 2) { + decimalPlaces = split[1].length; + } else { + decimalPlaces = 0; + } + precision = Math.pow(10, decimalPlaces); + }, + + determineValue: function(startPos, endPos, currentPos) { + var ratio = (currentPos - startPos) / (endPos - startPos); + var range = settings.max - settings.min; + var difference = Math.round(ratio * range / step) * step; + // Use precision to avoid ugly Javascript floating point rounding issues + // (like 35 * .01 = 0.35000000000000003) + difference = Math.round(difference * precision) / precision; + return difference + settings.min; + }, + + determinePosition: function(value) { + var ratio = (value - settings.min) / (settings.max - settings.min); + return Math.round(ratio * $(inner).width()) + $(trackLeft).position().left - offset; + }, + + setValue: function(newValue, triggeredByUser) { + if(typeof triggeredByUser === 'undefined') { + triggeredByUser = true; + } + if(settings.input) { + $(settings.input).val(newValue); + } + if(settings.onChange) { + settings.onChange(newValue, {triggeredByUser: triggeredByUser}); + } + }, + + setPosition: function(value) { + $(thumb).css({left: String(value) + 'px'}); + $(trackLeft).css({width: String(value + offset) + 'px'}); + }, + + rangeMousedown: function(mdEvent, isTouch, originalEvent) { + if( !$(element).hasClass('disabled') ) { + mdEvent.preventDefault(); + var left = $(inner).offset().left; + var right = left + $(inner).width(); + var pageX; + if(isTouch) { + pageX = originalEvent.originalEvent.touches[0].pageX; + } else { + pageX = (typeof mdEvent.pageX != 'undefined') ? mdEvent.pageX : originalEvent.pageX; + } + var value = module.determineValue(left, right, pageX); + if(pageX >= left && pageX <= right) { + module.setPosition(pageX - left - offset); + module.setValue(value); + } + var rangeMousemove = function(mmEvent) { + mmEvent.preventDefault(); + if(isTouch) { + pageX = mmEvent.originalEvent.touches[0].pageX; + } else { + pageX = mmEvent.pageX; + } + value = module.determineValue(left, right, pageX); + if(pageX >= left && pageX <= right) { + if(value >= settings.min && value <= settings.max) { + module.setPosition(pageX - left - offset); + module.setValue(value); + } + } + } + var rangeMouseup = function(muEvent) { + if(isTouch) { + $(document).off('touchmove', rangeMousemove); + $(document).off('touchend', rangeMouseup); + } else { + $(document).off('mousemove', rangeMousemove); + $(document).off('mouseup', rangeMouseup); + } + } + if(isTouch) { + $(document).on('touchmove', rangeMousemove); + $(document).on('touchend', rangeMouseup); + } + else { + $(document).on('mousemove', rangeMousemove); + $(document).on('mouseup', rangeMouseup); + } + } + }, + + setValuePosition: function(val, triggeredByUser) { + if(typeof triggeredByUser === 'undefined') { + triggeredByUser = true; + } + var position = module.determinePosition(val); + module.setPosition(position); + module.setValue(val, triggeredByUser); + }, + + invoke: function(query) { + switch(query) { + case 'set value': + if(queryArguments.length > 0) { + instance.setValuePosition(queryArguments[0], false); + } + break; + } + }, + + addVisibilityListener: function(elem) { + + // Add a mutation observer (https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) + // to detect when root invisible element is behing shown in order to initialize the thumb correctly + // when position and offets are available (https://stackoverflow.com/a/5974377) + + var observer = new MutationObserver(function(mutationList) { + if ($(elem).is(':visible')) { + observer.disconnect(); // Avoid infinite recursion because « module.setValuePosition » will trigger this observer + module.setValuePosition(settings.start); + } + }); + + var closestHiddenParent = $(elem).parentsUntil(':visible'); + + if (closestHiddenParent.length != 0) { + observer.observe(closestHiddenParent[closestHiddenParent.length - 1], {attributes: true}); + } + }, + + }; + + if(methodInvoked) { + if(instance === undefined) { + module.initialize(); + } + module.invoke(query); + } + else { + module.initialize(); + } + + }) + ; + + return this; + + }; + + $.fn.range.settings = { + + name : 'Range', + namespace : 'range', + + min : 0, + max : false, + step : 1, + start : 0, + input : false, + + onChange : function(value){}, + + }; + + +})( jQuery, window, document ); diff --git a/src/definitions/modules/range.less b/src/definitions/modules/range.less new file mode 100644 index 0000000000..c7380f6b28 --- /dev/null +++ b/src/definitions/modules/range.less @@ -0,0 +1,207 @@ +/*! + * # Semantic UI - Range + * http://github.com/semantic-org/semantic-ui/ + * + * + * Released under the MIT license + * http://opensource.org/licenses/MIT + * + */ + + +/******************************* + Theme +*******************************/ + +@type : 'module'; +@element : 'range'; + +@import (multiple) '../../theme.config'; + +/******************************* + Range +*******************************/ + +.ui.range { + height: @barHeight; + width: @barWidth; +} + +.ui.range .inner { + margin: @innerMargin; + height: @barHeight; + position: relative; +} + +.ui.range .inner:hover { + cursor: @hoverCursor; +} + +.ui.range .inner .track { + position: absolute; + height: @trackHeight; + width: @trackWidth; + border-radius: @trackBorderRadius; + top: 9px; + left: 0; + background-color: @trackColor; +} + +.ui.range .inner .track-fill { + position: absolute; + height: @trackHeight; + width: 0; + border-radius: @trackBorderRadius; + top: 9px; + left: 0; + background-color: @trackFillColor; +} + +.ui.range .inner .thumb { + position: absolute; + top: 0; + left: 0; + height: @thumbHeight; + width: @thumbWidth; + background: @thumbBackground; + border-radius: @thumbBorderRadius; + box-shadow: @thumbBoxShadow; +} + + +/*-------------- + Inverted +---------------*/ + +.ui.inverted.range .inner .track { + background-color: @invertedTrackColor; +} + +.ui.inverted.range .inner .track-fill { + background-color: @invertedTrackFillColor; +} + + +/*-------------- + Colors +---------------*/ + +/* Red */ +.ui.red.range .inner .track-fill { + background-color: @red; +} +.ui.red.inverted.range .inner .track-fill { + background-color: @lightRed; +} + +/* Orange */ +.ui.orange.range .inner .track-fill { + background-color: @orange; +} +.ui.orange.inverted.range .inner .track-fill { + background-color: @lightOrange; +} + +/* Yellow */ +.ui.yellow.range .inner .track-fill { + background-color: @yellow; +} +.ui.yellow.inverted.range .inner .track-fill { + background-color: @lightYellow; +} + +/* Olive */ +.ui.olive.range .inner .track-fill { + background-color: @olive; +} +.ui.olive.inverted.range .inner .track-fill { + background-color: @lightOlive; +} + +/* Green */ +.ui.green.range .inner .track-fill { + background-color: @green; +} +.ui.green.inverted.range .inner .track-fill { + background-color: @lightGreen; +} + +/* Teal */ +.ui.teal.range .inner .track-fill { + background-color: @teal; +} +.ui.teal.inverted.range .inner .track-fill { + background-color: @lightTeal; +} + +/* Blue */ +.ui.blue.range .inner .track-fill { + background-color: @blue; +} +.ui.blue.inverted.range .inner .track-fill { + background-color: @lightBlue; +} + +/* Violet */ +.ui.violet.range .inner .track-fill { + background-color: @violet; +} +.ui.violet.inverted.range .inner .track-fill { + background-color: @lightViolet; +} + +/* Purple */ +.ui.purple.range .inner .track-fill { + background-color: @purple; +} +.ui.purple.inverted.range .inner .track-fill { + background-color: @lightPurple; +} + +/* Pink */ +.ui.pink.range .inner .track-fill { + background-color: @pink; +} +.ui.pink.inverted.range .inner .track-fill { + background-color: @lightPink; +} + +/* Brown */ +.ui.brown.range .inner .track-fill { + background-color: @brown; +} +.ui.brown.inverted.range .inner .track-fill { + background-color: @lightBrown; +} + +/* Grey */ +.ui.grey.range .inner .track-fill { + background-color: @grey; +} +.ui.grey.inverted.range .inner .track-fill { + background-color: @lightGrey; +} + +/* Black */ +.ui.black.range .inner .track-fill { + background-color: @black; +} +.ui.black.inverted.range .inner .track-fill { + background-color: @lightBlack; +} + + +/*-------------- + Disabled +---------------*/ +.ui.range.disabled { + opacity: @disabledOpacity; +} + +.ui.range.disabled .inner:hover { + cursor: auto; +} + +.ui.range.disabled .inner .track-fill { + background: @disabledTrackFillColor; +} diff --git a/src/semantic.less b/src/semantic.less index c646474427..64e85817e2 100644 --- a/src/semantic.less +++ b/src/semantic.less @@ -57,6 +57,7 @@ & { @import "definitions/modules/nag"; } & { @import "definitions/modules/popup"; } & { @import "definitions/modules/progress"; } +& { @import "definitions/modules/range"; } & { @import "definitions/modules/rating"; } & { @import "definitions/modules/search"; } & { @import "definitions/modules/shape"; } diff --git a/src/themes/default/modules/range.overrides b/src/themes/default/modules/range.overrides new file mode 100644 index 0000000000..14fb0da124 --- /dev/null +++ b/src/themes/default/modules/range.overrides @@ -0,0 +1,3 @@ +/******************************* + Theme Overrides +*******************************/ diff --git a/src/themes/default/modules/range.variables b/src/themes/default/modules/range.variables new file mode 100644 index 0000000000..c5979a64ab --- /dev/null +++ b/src/themes/default/modules/range.variables @@ -0,0 +1,30 @@ +/******************************* + Range +*******************************/ + +@barHeight: 20px; +@barWidth: 100%; + +@innerMargin: 0 10px 0 10px; + +@hoverCursor: pointer; + +@trackHeight: 4px; +@trackWidth: 100%; +@trackBorderRadius: @absoluteBorderRadius; +@trackColor: rgba(0, 0, 0, .05); +@trackFillColor: @black; + +@thumbHeight: 20px; +@thumbWidth: 20px; +@thumbBackground: #fff linear-gradient(transparent, rgba(0, 0, 0, 0.05)); +@thumbBorderRadius: 100%; +@thumbBoxShadow: 0 1px 2px 0 rgba(34,36,38,.15),0 0 0 1px rgba(34,36,38,.15) inset; + +/* Inverted */ +@invertedTrackColor: rgba(255,255,255,.08); +@invertedTrackFillColor: @lightBlack; + +/* Disabled */ +@disabledOpacity: .5; +@disabledTrackFillColor: @grey; diff --git a/tasks/config/admin/release.js b/tasks/config/admin/release.js index 94ee736117..d74b24e322 100644 --- a/tasks/config/admin/release.js +++ b/tasks/config/admin/release.js @@ -92,6 +92,7 @@ module.exports = { 'popup', 'progress', 'rail', + 'range', 'rating', 'reset', 'reveal', diff --git a/tasks/config/defaults.js b/tasks/config/defaults.js index 2c0e9ebfbd..115009c8c4 100644 --- a/tasks/config/defaults.js +++ b/tasks/config/defaults.js @@ -90,6 +90,7 @@ module.exports = { 'nag', 'popup', 'progress', + 'range', 'rating', 'search', 'shape', diff --git a/tasks/config/project/install.js b/tasks/config/project/install.js index 6dbf9c9d07..ff60a5c1cb 100644 --- a/tasks/config/project/install.js +++ b/tasks/config/project/install.js @@ -391,6 +391,7 @@ module.exports = { { name: "nag", checked: true }, { name: "popup", checked: true }, { name: "progress", checked: true }, + { name: "range", checked: true }, { name: "rating", checked: true }, { name: "search", checked: true }, { name: "shape", checked: true }, From f4e1073166cd1c14410a30c85d260bebfdc9ca27 Mon Sep 17 00:00:00 2001 From: Sean Hamilton Date: Sat, 28 Jul 2018 02:35:23 +0100 Subject: [PATCH 3/5] Added release note --- RELEASE-NOTES.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index 847f6991ca..5c1369be78 100755 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -6,6 +6,11 @@ - Calendar Component - Range Slider Component +### Version 2.5.0 - DATE, HERE + +**Major Enhancements** +- Added range slider component created by **@tyleryasaka** :level_slider: **Thanks @hammy2899** [#1336](https://github.com/Semantic-Org/Semantic-UI/issues/1336) + ### Version 2.4.4 - July 26, 2018 **Enhancements** From c671f21c789ddcda2ae3c5657fdd7414eddb3333 Mon Sep 17 00:00:00 2001 From: Sean Hamilton Date: Sat, 28 Jul 2018 02:39:54 +0100 Subject: [PATCH 4/5] Added range component to theme.config.example --- src/theme.config.example | 1 + 1 file changed, 1 insertion(+) diff --git a/src/theme.config.example b/src/theme.config.example index 0e5360a263..3856937dc9 100644 --- a/src/theme.config.example +++ b/src/theme.config.example @@ -56,6 +56,7 @@ @nag : 'default'; @popup : 'default'; @progress : 'default'; +@range : 'default'; @rating : 'default'; @search : 'default'; @shape : 'default'; From 704b1e168f784deb40dcad92573af60c18d5c34c Mon Sep 17 00:00:00 2001 From: Sean Date: Thu, 16 Aug 2018 14:42:30 +0100 Subject: [PATCH 5/5] Added header comment --- src/definitions/modules/range.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/definitions/modules/range.js b/src/definitions/modules/range.js index 50956e7324..df9eabba99 100644 --- a/src/definitions/modules/range.js +++ b/src/definitions/modules/range.js @@ -1,5 +1,10 @@ /*! - * # Range slider for Semantic UI. + * # Semantic UI - Range + * http://github.com/semantic-org/semantic-ui/ + * + * + * Released under the MIT license + * http://opensource.org/licenses/MIT * */