SOW : Utils

SOW = Step Of Web (Smarty author).
SOW plugins are part of Smarty Core, written from scratch!

Info

A collection of useful tools, as light as possible!

Main purpose: cut backend coding & processing!
Example: avatar initials would be parsed in a backend loop! Why not doing this on client side?


/* 
	:: Plugin File
	src/js/sow.core/sow.utils.js

	:: Plugin Init
*/	$.SOW.core.utils.init();
									

Simple Background Slideshow

Simple background image slideshow (as cover) written from scratch (1.5Kb final size)! Mobile supported with different set of images!
Please note: Images are loaded on page load, so is not recommended to use too many images or too many slideshows on the same page! Depends on total size!

There are no controlls! Just a simple slideshow!

data-sow-slideshow-interval="3000"
data-sow-slideshow-fade-delay="1500"
data-sow-slideshow-interval="8000"
data-sow-slideshow-fade-delay="3000"
<!-- 
Please note, position-relative of main container, if something goes wrong 
Anjust overlay (darknes or lightness if .overlay-light used instead):	
	overlay-opacity-[0-9]

Also note: in this example, we have 300px width/height! 
Because is a background image, width/height should be set/known.

Real example of this script: niche.restaurant.html
-->
<div class="sow-util-slideshow position-relative w--300 h--300 overlay-dark overlay-opacity-3" 
	data-sow-slideshow-interval="3000" 
	data-sow-slideshow-fade-delay="1500" 
	data-sow-slideshow="
		demo.files/images/unsplash/restaurant/thumb_600/jade-wulfraat-sIzym-INcvk-unsplash-min-min.jpg,
		demo.files/images/unsplash/restaurant/thumb_600/jade-wulfraat-UaOPeqfdW1c-unsplash-min-min.jpg,
		.demo.files/images/unsplash/restaurant/thumb_600/jade-wulfraat-yXnPoTkkY94-unsplash-min-min.jpg
	">
</div>


<!-- 

	Using mobile attribute for smaller image size 
	(~768px is ok) 

-->
<div class="sow-util-slideshow position-relative w--300 h--300 overlay-dark overlay-opacity-3" 
	data-sow-slideshow-interval="3000" 
	data-sow-slideshow-fade-delay="1500" 
	data-sow-slideshow="
		demo.files/images/unsplash/restaurant/jade-wulfraat-sIzym-INcvk-unsplash-min-min.jpg,
		demo.files/images/unsplash/restaurant/jade-wulfraat-UaOPeqfdW1c-unsplash-min-min.jpg,
		demo.files/images/unsplash/restaurant/jade-wulfraat-yXnPoTkkY94-unsplash-min-min.jpg
	"
	data-sow-slideshow-xs="
		demo.files/images/unsplash/restaurant/thumb_600/jade-wulfraat-sIzym-INcvk-unsplash-min-min.jpg,
		demo.files/images/unsplash/restaurant/thumb_600/jade-wulfraat-UaOPeqfdW1c-unsplash-min-min.jpg,
		demo.files/images/unsplash/restaurant/thumb_600/jade-wulfraat-yXnPoTkkY94-unsplash-min-min.jpg
	"
	>
</div>
									

Initials by attribute

Extract the full name and inject the initials only.

Manual/static color

Asign color by name
Manual/static color

Asign color by name
<!-- circle elements: replace .rounded with .rounded-circle -->
<span data-initials="John Doe" class="sow-util-initials bg-danger-soft rounded h5 w--40 h--40 d-inline-flex justify-content-center align-items-center">
	<i class="fi fi-circle-spin fi-spin"></i>
</span>


<!-- 
	Assign color by name 

	by default we set .bg-light as a default background color!
	Is replaced by the plugin with actual name color!
-->
<span data-initials="John Doe" data-assign-color="true" class="sow-util-initials bg-light rounded h5 w--40 h--40 d-inline-flex justify-content-center align-items-center">
	<i class="fi fi-circle-spin fi-spin"></i>
</span>
									

Cookies by attribute

Add, delete and toggle cookies using a button/link

Set Cookie Set Delete Toggle
<!-- 
	data-cookie-val  		is set by defatul to "1" if not provided!
	data-cookie-expire 		(in days) is set by default to 7 if not pvided!
	data-cookie-path="/" 		(cookie path, default "/")

Note: toast is optional!
	data-toast-msg-type-set="primary|success|warning|danger" (default: success)
	data-toast-msg-type-del="primary|success|warning|danger" (default: success)
-->



<!-- add cookie -->
<a href="#" class="sow-util-cookie"
	data-cookie-set="_test_" 
	data-cookie-val="1" 
	data-cookie-expire="1" 

	data-toast-msg-set="Set: _test_" 
	data-toast-msg-pos="top-center" 
	data-toast-msg-type-set="success-soft">
	Set Cookie
</a>

<!-- delete cookie -->
<a href="#" class="sow-util-cookie"
	data-cookie-del="_test_" 

	data-toast-msg-del="Deleted: _test_" 
	data-toast-msg-pos="top-center" 
	data-toast-msg-type-del="danger-soft">
	Set Delete
</a>

<!-- toggle cookie -->
<a href="#" class="sow-util-cookie"
	data-cookie-toggle="_test_" 
	data-cookie-val="1" 
	data-cookie-expire="1" 

	data-toast-msg-set="Set: _test_" 
	data-toast-msg-del="Deleted: _test_" 
	data-toast-msg-pos="top-center"
	data-toast-msg-type-set="success-soft" 
	data-toast-msg-type-del="danger-soft">
	Toggle
</a>
									


	/*
	programatically 
	Cookie Plugin is added as Core in Smarty:
	https://github.com/js-cookie/js-cookie
	So you can also use directly in your app:
	*/

	Cookies.set('key', 'val', { expires: 365, path: '/' });
	Cookies.get('key');
	Cookies.remove('key', { path: '/' });


	/*
		IMPORTANT! 'SameSite=None; secure'
		You can pass the Google params in path.
		And you can use the global variable:
		$.SOW.globals.cookie_secure
	*/

	Cookies.set('key', 'val', { expires: 365, path: $.SOW.globals.cookie_secure });
	Cookies.get('key', { path: $.SOW.globals.cookie_secure });
	Cookies.remove('key', { path: $.SOW.globals.cookie_secure });
									

Time ago






<!-- 
	WAYS TO SET THE LANGUAGE 
	(default is already english ; can be changed in gulp.config__core.js)

		1. by data attribute, as you can see the working example below (will overwrite anything)
		2. by javascript
			<script>
				var sow_util_timeago_lang = {
					seconds 		: "less than a minute ago",
					minute 			: "about a minute ago",
					minutes 		: "%d minutes ago",
					hour 			: "about an hour ago",
					hours 			: "about %d hours ago",
					day 			: "a day ago",
					days 			: "%d days ago",
					month 			: "about a month ago",
					months 			: "%d months ago",
					year 			: "about a year ago",
					years 			: "%d years ago"
				}
			</script>

		3. by empty span tag
				<span class="hide sow-util-timeago-lang" data-lang='{
					"seconds" 		: "less than a minute ago",
					"minute" 		: "about a minute ago",
					"minutes" 		: "%d minutes ago",
					"hour" 			: "about an hour ago",
					"hours" 		: "about %d hours ago",
					"day" 			: "a day ago",
					"days" 			: "%d days ago",
					"month" 		: "about a month ago",
					"months" 		: "%d months ago",
					"year" 			: "about a year ago",
					"years" 		: "%d years ago"
				}'>

		2 & 3 – used for multilanguage portal, if multiple timeago are used.
		Set it once anywhere, for each page that timeago is required!
		You can also change the default (english) in gulp.config__core.js and rebuild using GULP

	

	data-live="true" 	will update in realtime (1min. loop)

-->
<time class="sow-util-timeago" 
	datetime="2019-09-17T23:59:17" 
	data-live="true" 
	data-lang='{
		"seconds" 		: "less than a minute ago",
		"minute" 		: "about a minute ago",
		"minutes" 		: "%d minutes ago",
		"hour" 			: "about an hour ago",
		"hours" 		: "about %d hours ago",
		"day" 			: "a day ago",
		"days" 			: "%d days ago",
		"month" 		: "about a month ago",
		"months" 		: "%d months ago",
		"year" 			: "about a year ago",
		"years" 		: "%d years ago"
	}'></time>


<!-- using abbr -->
<abbr class="sow-util-timeago" data-time="December 17, 2012">December 17, 2012</abbr>
<abbr class="sow-util-timeago" data-time="2011-12-17T09:24:17Z"></abbr> 

<!-- using span (and timestamp example) -->
<span class="sow-util-timeago" data-time="1372218564"></span>

Note: any date format is working on any tag: span, abbr, etc.
Here are just few examples of using them!

									

Element Cloner Hint: create some clones and then drag to reorder

Self Cloning
Outside Cloning (hidden element as `template`)
Note: this example is simple, no buttons

ADD ELEMENT

<!-- 
	
	Attributes 

	data-clone-target="..."  				what to clone
	data-clone-destination="..."  		where to append the clone
	data-clone-sortable="true" 				true = reorder on drag/drop
	data-clone-limit="0"  				max no. of clones
	data-clone-method="append"  			append|prepend (default: append)

	.sow-util-cloner class is required on "+" button/link
	.btn-clone-remove class is required only for the second example (not for self cloning)


	IMPORTANT! (see example 2)
		If a field is datepicker, colorpicker (or anything else),
		the plugin should know what to reinit for each clone! Will not work for "self cloning"
		so the second example with a hidden element should be used instead.

		We can't add .datepicker class directly because will be initialized on
		page load and the clone will be wrong! So we add this attribute instead of a direct class:
	 		data-cloned-replace-class="datepicker"

	 Other examples:
	 	data-cloned-replace-class="bs-select"	(for selects)
	 	data-cloned-replace-class="rangepicker"
	 	data-cloned-replace-class="colorpicker"
	 	... and so on
-->





<!-- 1. Self Cloning -->
<div id="container_clone_example">

	<div class="input-group mb-3">
		<input type="text" class="form-control" placeholder="Recipient's username">

		<div class="input-group-append">
			<a href="#" 

				data-clone-target="#container_clone_example" 
				data-clone-destination="#container_clones"  
				data-clone-sortable="true" 
				data-clone-limit="0" 
			
				class="sow-util-cloner btn btn-outline-secondary">
				<!-- 
					note: icon class replaced when cloned
					attribute not limited to icon - can be added to any element inside clone
				 -->
				<i class="fi fi-plus m-0" data-cloned-replace-class="fi fi-close m-0"></i>
			</a>
		</div>
	</div>

</div>

<div id="container_clones"><!-- clones appended here --></div>
									

<!-- 2. Outside Cloning (hidden element as `template`) -->
<a href="#" 

	data-clone-target="#container_tpl_hidden>div" 
	data-clone-destination="#container_clones2"  
	data-clone-sortable="true" 
	data-clone-limit="5" 

	class="sow-util-cloner">
	ADD ELEMENT
</a>

<div id="container_clones2"><!-- clones appended here --></div>

<!-- hidden container containing the `template` to be cloned -->
<div id="container_tpl_hidden" class="hide">
	
	<!-- this will be cloned -->
	<div class="clearfix mb-3"><!-- always wrap elements inside a div/container -->
		<input type="text" class="form-control" data-cloned-replace-class="form-control rangepicker">
		<a href="#" class="btn-clone-remove">remove</a>
	</div>

</div>
									
<!-- PREADDED ITEMS 
Preadded items should be present inside the clone container and 
this is the strucuture (for the first example):
-->
<div id="container_clones">
	<div class="js-cloned">

		<input type="text" class="form-control">

		<a href="#" data-clone-target="#container_clone_example">remove</a>

	</div>
</div>
									

Action Util

Many util functions for a single button/checkbox/etc. Slightly similar with SOW : Button Toggle plugin but extended, more options and more flexible.


<!-- EMAIL ADDRESS -->
<div class="input-group-over">

	<div class="form-label-group">
		<input required readonly placeholder="Email Address" id="account_email" name="account[email]" type="email" class="form-control" value="john.doe@gmail.com">
		<label for="account_email"><span class="text-danger">Email</span> Address</label>
	</div>

	<a id="email_edit_show" href="#!" class="btn transition-none sow-util-action" 
		data-util-self-ignore="true" 
		data-util-target-hide="#email_edit_show" 
		data-util-target-show="#email_edit_hide, #email_edit_password_request" 
		data-util-target-readonly-off="#account_email" 

		data-util-target-input="#account_email" 
		data-util-target-input-val="" 

		data-util-target-focus="#account_email">
		<i class="fi fi-pencil m-0"></i>
	</a>

	<a id="email_edit_hide" href="#!" class="btn transition-none sow-util-action hide" 
		data-util-self-ignore="true" 
		data-util-target-hide="#email_edit_hide, #email_edit_password_request" 
		data-util-target-show="#email_edit_show" 
		data-util-target-readonly-on="#account_email" 

		data-util-target-input="#account_email" 
		data-util-target-input-val="john.doe@gmail.com">
		<i class="fi fi-close m-0"></i>
	</a>

</div>


<div id="email_edit_password_request" class="mt-3 hide">

	<!-- password -->
	<div class="input-group-over">
		<div class="form-label-group mb-3">
			<input placeholder="Account Password" id="account_password" name="account[current_password]" type="password" class="form-control">
			<label for="account_password">Account Password</label>
		</div>

		<!-- Show Password -->
		<a href="#" class="btn btn-password-type-toggle" data-target="#account_password">
			<span class="group-icon">
				<i class="fi fi-eye m-0"></i>
				<i class="fi fi-close m-0"></i>
			</span>
		</a>
	</div>
	<!-- /password -->

</div>
											
<!-- AVAILABLE OPTIONS -->


<!-- Do not toggle self "active" class : on button click -->
data-util-self-ignore="true"

<!-- Show/Hide -->
data-util-target-hide="#container" 
data-util-target-show="#container" 

<!-- Add Class -->
data-util-target-class-add="#container" 
data-util-target-class-add-val="someclass" 

<!-- Remove Class -->
data-util-target-class-remove="#container" 
data-util-target-class-remove-val="someclass" 

<!-- Toggle Class -->
data-util-target-class-toggle="#container" 
data-util-target-class-toggle-val="someclass" 

<!-- Input/Textarea Value -->
data-util-target-input="#inputElement" 
data-util-target-input-val="someValue" 

<!-- Input/Textarea Placeholder -->
data-util-target-placeholder="#inputElement" 
data-util-target-placeholder-val="someValue" 

<!-- Readonly Attribute -->
data-util-target-readonly-on="#inputElement" 
data-util-target-readonly-off="#inputElement" 
data-util-target-readonly-toggle="#inputElement" 

<!-- Disabled Attribute -->
data-util-target-disable-on="#element" 
data-util-target-disable-off="#element" 
data-util-target-disable-toggle="#element" 

<!-- Remove Container -->
data-util-target-remove="#container" 

<!-- Focus Input/Textarea -->
data-util-target-focus="#inputElement" 

<!-- Toast Message on click (different then ajax toast) -->
data-util-toast-msg="Item Changed" 
data-util-toast-position="top-center" 
data-util-toast-type="success" 
data-util-toast-timeout="2500" 

<!-- Ajax Request -->
data-util-ajax-request="URL_HERE"
data-util-ajax-method="GET"
data-util-ajax-params="['param1','value1']['param2','value2']"
data-util-ajax-toast-success="Successfully Updated!"
data-util-ajax-toast-position="top-center"
data-util-ajax-toast-timeout="2500"