Skip to content

Instantly share code, notes, and snippets.

@shithee
Last active July 11, 2020 06:02
Show Gist options
  • Save shithee/aadb9977c8c92e7ccc9aa9226f22e1e2 to your computer and use it in GitHub Desktop.
Save shithee/aadb9977c8c92e7ccc9aa9226f22e1e2 to your computer and use it in GitHub Desktop.
The one solution for date picker, multi selector with image and simple single page application with forward and backward options.

Guide for One.js

One.js covers the below functionalities in a single file.

  1. Single page maker
  2. Todoist like datetime picker
  3. Multiple selector with image option and multiple values.

Single page maker

By using this library we can easily make our html application into single page application. Here is the list of things used in this functionality.

  • onepage - Used to identify the application when to use the function. if the data is empty then use the default tag .
  • onecontainer - Used to inform the function where to load the page content. Function set as default .
  • opt - Used to opt out from the functionality in a particular tag. Page will reloaded in that case. Default set as false.
  • button - Used to exclude the ajax button. Function will not executed if its true. Has default as false.
  • menu - Used to make a particular menu active. It will add active class to the menu selector.
  • navigation - Used to hide all the other menu inactive. It will work if menu was set.
  • URL - The url in the href tag used as URL.

Usage

let see the below html Example.

<html>
    <title>One.js single page application</title>
    <body data-onepage=".menu" data-onecontainer="#container" data-navigation=".menu">
        <a class="menu" data-button="true">Ajax Button - Will do the other events.</a>
        <a class="menu" href="fb.com" data-opt="true">Optout Button - Will redirect fb.com </a>
        <a class="menu change" data-menu=".change">
            Change Menu - Will make this menu as active, so this tag will be activated
        </a>
        <a class="menu" data-container="#special" href="/special">
            This will load the page **/special** into #special container
        </a>
        <a class="otherclass" href="/normal">Will work as normal a tag </a>
        <div id="#container">
           This is where content will be loaded. 
           All page content will be loaded here, except tag with inline container.
        </div>
        <div id="#special">
           This is where the special content will be loaded.
        </div>
    </body>
</html>

How to use this in forms?

This library also have an option to use the single page functionality in reloadable form submissions. To enable we just need to add a class to the form.

  <form type="GET" class="oneform" data-location="#container_to_paste">
   ...
  </form>

Notes for One form

  • This one form functionlity just works only in get type forms
  • It will act like normal form get form submission with query parameters
  • We can change the container location if we need to by using data-location=""

One selector

This multiple selector used to the alternative solution for select2. In this selector we can use image and get the selected value in any format we want.

How to use this ?

To enable this frame work we just need a selector and the option data. The framework will do the work for you.

To activate the selector and initialize the options

let options = {
   'data' : data, //in js object array { required }
   'required' : ['id','name'], // Use this index only { optional }
   'icon' : 'image', // image index { optional }
   'name' : 'name' // name index { required }
}
$(".some-selector").options(options);

To set the selected values

$(".some-selector").selected(data,"name index"); { required both }

To validate the selectors

In this selector we can validate this in two ways.

  • data-min : It used to set the minimum set the minimum selected options. This need to be added in the home selector. If the condition failed then it will return false in fetching the result.
<div id="some-selector" data-min="1"> <!-- optional -->
  • data-limit : It used to set the maximum select options. This need to be added in the home selector. If the condition failed then it will remove the first selected value from the input.
<div id="some-selector" data-limit="3"> <!-- optional -->

To get the selected options

By using this function we can get the selected value and its other property values. We can map the values and customize it based our needs.

let options = {
   'required' : [ 'id', 'name' ],
   'map' : { id : 'team-id', name : 'team-name' }
}
$(".some-selector").get_c(options);

To get the all options from the container

By using this function we can get the all options value and its other property values. We can map the values and customize it based our needs.

let options = {
   'required' : [ 'id', 'name' ],
   'map' : { id : 'team-id', name : 'team-name' }
}
$(".some-selector").get_o(options);
To make the remove option work

Right now there is a bug in the framework and it will be solved soon. But now include this two lines in the page to enable remove option.

$(document).on("click", ".label-info", function() {
    $(this).remove();
});

One date picker

By using this function we can get the date picker like todoist. It will return the JS date object of human input. And it will parse the human input when we enter . [Dot]

To activate the one date picker

To avtivate the picker just need to call the function.

$(".some-selector").onedate();

How to use this ?

To use this frame work we need to write the date in computer readable format. Here is the list of acceptable format in the funation.

  • 13 jun 2020 8:31am.
  • 13 jun 2020 8pm.
  • 13 jun 2020.
  • jun 2020.
  • 13 jun.

Things to Do

  1. Need to make this work with meta content and title.
  2. Forward or Backward buttons will not work if page reloaded. Need to solve this bug.
  3. make selector option close working.
$(document).ready(function(){
var is_single = $("[data-onesingle]").data('onesingle');
var oneselector = $("[data-onepage]").data('onepage'); // selector for page load
oneselector = (oneselector) ? oneselector : 'a';
var globalcontainer = $("[data-onecontainer]").data('onecontainer'); // container where put loaded content
globalcontainer = (globalcontainer) ? globalcontainer : 'body';
var navigation = $("[data-navigation]").data('navigation'); // For remove active tag in menu
var loader = $("[data-oneloader]").data('oneloader');
if(is_single){
$(document).on("click", oneselector , function(e) {
e.preventDefault();
var data = $(this).data();
var container = (data['location']) ? data['location'] : globalcontainer; // For a different container
var url = $(this).attr('href');
$(container).find('*').not(loader).remove();
(loader) && $(loader).show();
if(data['button']){ // For ajax buttons
return false;
}
if($(this).data('opt') == true){
window.location.href = url;
return false;
}
if(data['menu']){ // Make a menu active
$(navigation).removeClass('active');
$(data['menu']).addClass('active');
}
$.get(url,function(data){
$(container).html(data);
window.history.pushState({ container, url },"", url);
(loader) && $(loader).hide();
})
return false;
})
window.onpopstate = function(e){
if(e.state){
$.get(e.state.url,function(data){
$(e.state.container).html(data);
})
return false;
}
};
}
$(document).on('submit', '.oneform', function(e) {
e.preventDefault();
let url = window.location.href;
let data = $(this).data();
let container = (data['location']) ? data['location'] : globalcontainer;
(loader) && $(loader).show();
url = (['?','#'].includes(url.slice(-1))) ?
url.substring(0,url.length - 1) : url;
url = `${url}?${$(this).serialize()}`;
$.get(url,function(data){
$(container).html(data);
window.history.pushState({ container, url },"", url);
(loader) && $(loader).hide();
})
return false;
});
$(document).on("click", ".bootstrap-tagsinput", function() {
let container = $(this).parent().data("container");
let reference = $(`${container}`).data('reference');
if (reference) {
let data = get_container_choice($(reference));
create_container_options({
options : data,
icon: false,
name: 'reference-name'
},$(container));
}
$(`${container} .event-list-wrapper`).toggle();
})
$(document).on("click", ".event-list", function() {
let data = $(this).data();
let container = $(this).parent().parent().data("container");
let wrapper = $(this).parent();
let name = $(this).find('.event-text').text();
if(! validate_the_limit($(`${container}`))){
$(container).find('.bootstrap-tagsinput > .tag').first().remove();
}
show_selected_choice(data,$(`${container}`),name);
wrapper.hide();
});
$(document).on("click", ".label-info", function() {
});
$(document).on("keyup", ".one-time", function() {
var input = $(this).val();
if(input.slice(-1) == "."){
input = input.substring(0, input.length - 1);
input = format_human_time(input);
$(this).val(input);
}
});
$.fn.options = function (data) {
create_container_options(data,this);
return this;
};
$.fn.selected = function (data, index = "name"){
if(!data) return false;
data.map( v => {
show_selected_choice(v,this,v[index]);
});
}
$.fn.get_o = function(options=null){
let data = get_container_option(this,false);
return modify(data,options);
}
$.fn.get_c = function(options=null){
if(! validate_the_min(this)){
return false;
}
let data = get_container_choice(this,false);
return modify(data,options);
}
$.fn.onedate = function(){
this.addClass('one-time');
}
})
function modify(data,options){
let modified = [];
if(options && data){
data.map( obj => {
let single = {};
if(options.required && options.required.length){
$.each( obj, function(k,v){
let key = (options.map[k]) ? options.map[k] : k;
if(options.required.includes(k)){
single[key] = v;
}
});
}
modified.push(single);
})
}else{
modified = data;
}
return modified;
}
function validate_the_limit(element){
let limit = element.data('limit');
let i = 0;
if(limit){
element.find('.bootstrap-tagsinput').find('.label-info').each( function(){
i++;
});
}
return ( !limit || (i<limit) ) ? true : false;
}
function validate_the_min(element){
let min = element.data('min');
let i = 0;
if(limit){
element.find('.bootstrap-tagsinput').find('.label-info').each( function(){
i++;
});
}
return ( !min || (i >= min) ) ? true : false;
}
function create_container_options(data,element){
if(!data.options) return false;
if(!element.find('.event-list-wrapper').length){
element.append(`<div class="event-list-wrapper"></div>`);
}
if(!element.find('.bootstrap-tagsinput').length){
element.find('[data-role="tagsinput"]').hide();
element.find('.event-list-wrapper').before(
`<div class="bootstrap-tagsinput"><input type="text" placeholder=""></div>`
);
}
element.find('.event-list-wrapper').empty();
data.options.map(obj => {
let data_string = "";
$.each( obj, function(k,v){
if( data.required && !data.required.includes(k)) return true;
data_string += `data-${k}="${v}" `;
});
element.find('.event-list-wrapper').append(
`<div class="event-list" ${data_string}>
<img class="profile-img img-sm img-rounded mr-2"
src="${ (data.icon && obj[data.icon]) ? obj[data.icon] : `/assets/img/question.png` }"
alt="profile image">
<p class="event-text">${obj[data.name]}</p>
</div>`
);
})
}
// Called when user clicks an option
function show_selected_choice(data,element,name){
if(!data) return false;
let data_string = "";
$.each( data, function(k,v){
data_string += `data-${k}="${v}" `;
});
// var limit = $(`#${container}`).data('limit');
// if(limit){
// let selected = fetch_options(container);
// (limit < selected.length + 1) && $(`#${container} .bootstrap-tagsinput > .tag`).first().remove();
// }
if(!element.find('.bootstrap-tagsinput').length){
element.find('[data-role="tagsinput"]').hide();
element.find('.event-list-wrapper').before(
`<div class="bootstrap-tagsinput"><input type="text" placeholder=""></div>`
);
}
element.find('.bootstrap-tagsinput').append(
`<span class="tag label label-info" ${data_string}>
${name}
<span data-role="remove"></span>
</span>`
);
}
// Used to get a particular container options
function get_container_option(element,extra=true){
let options = [];
element.find('.event-list-wrapper').find('.event-list').each( function(){
let data = $(this).data();
if(extra == true){
data['reference-name'] = $(this).find('.event-text').text();
data['reference-img'] = $(this).find('.profile-img').attr("src");
}
options.push(data);
})
return options;
}
// Used to select a particular container selections
function get_container_choice(element,extra=true){
let options = [];
element.find('.bootstrap-tagsinput').find('.label-info').each( function(){
let data = $(this).data();
if(extra == true){
data['reference-name'] = $(this).text();
}
options.push(data);
})
return options;
}
function format_human_time(input){
let input_arr = (typeof input == "string") ? input.split(' ') : []
let month = ["jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"]
let obj = { hour : 0, mins : 0 }
let today = new Date();
input_arr.map(function(i) {
if (/^\d+$/.test(i)) {
obj.day = (parseInt(i) <= 31) ? parseInt(i) : today.getDate();
obj.year = (parseInt(i) > 24) ? parseInt(i) : today.getFullYear();
} else if (i.endsWith("am") || i.endsWith("pm")) {
let time_arr = i.split(":")
let add_time = (i.slice(-2) == "am") ? 0 : 12;
obj.hour = (time_arr[0]) ? parseInt(time_arr[0]) + add_time : 0;
obj.mins = (time_arr[1]) ? parseInt(time_arr[1]) + add_time : 0;
} else
obj.month = (typeof i == "string" && i.length == 3) ? month.indexOf(i) : today.getMonth();
})
let date = new Date(obj.year,obj.month,obj.day,obj.hour,obj.mins);
return date;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment