JsTag

Developer
Size
7,050 Kb
Views
30,360

How do I make an jstag?

Http://eranhirs.github.io/jsTag/ https://github.com/eranhirs/jsTag http://eranhirs.github.io/jsTag/assets/angular-typeahead.js. What is a jstag? How do you make a jstag? This script and codes were developed by Kevin on 28 August 2022, Sunday.

JsTag Previews

JsTag - Script Codes HTML Codes

<!DOCTYPE html>
<html >
<head> <meta charset="UTF-8"> <title>jsTag</title> <link rel="stylesheet" href="css/style.css">
</head>
<body> <div class="bs-example"> <div ng-controller="MoreControlController"> <js-tag js-tag-options="jsTagOptions"></js-tag> Number of tags: {{tags.getNumberOfTags()}} </div>
</div>
<!--
<div class="bs-example"> <div ng-controller="CustomizedController"> <js-tag js-tag-options='{ "texts": {"inputPlaceHolder": "Type text here"}, "defaultTags": ["Default Tag #1", "Default Tag #2"]}'> </js-tag> </div>
</div>
<div class="bs-example"> <div ng-controller="NoneditableController"> <js-tag js-tag-options="jsTagOptions"></js-tag> </div>
</div>
<div class="bs-example"> <div ng-controller="TypeaheadController"> <js-tag js-tag-mode="typeahead" js-tag-options="jsTagOptions"></js-tag> Number of tags: {{tags.getNumberOfTags()}} </div>
</div>
--> <script src='http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.14/angular.min.js'></script>
<script src='http://eranhirs.github.io/jsTag/assets/angular-typeahead.js'></script> <script src="js/index.js"></script>
</body>
</html>

JsTag - Script Codes CSS Codes

/* * Container * Explaining some of the CSS: # background-color: #FFFFFF; | To simulate an input box - in case background of the whole page is different
*/
.jt-editor { padding: 6px 12px 5px 12px; display: block; height: auto; vertical-align: middle; font-size: 14px; line-height: 1.428571429; color: #555; border: 1px solid #BFBFBF; border-radius: 2px; cursor: text; background-color: #FFFFFF;
}
.jt-editor.focused-true { border-color: #66AFE9; outline: 0;
}
/* Tag */
.jt-tag { background: #DEE7F8; border: 1px solid #949494; padding: 0px 0px 20px 2px; cursor: default; display: inline-block; -webkit-border-radius: 2px 3px 3px 2px; -moz-border-radius: 2px 3px 3px 2px; border-radius: 2px 3px 3px 2px; height: 22px;
}
/* Because bootstrap uses it and we don't want that if bootstrap is not included to look different */
.jt-tag { box-sizing: border-box;
}
.jt-tag:hover { border-color: #BCBCBC;
}
/* Value inside jt-tag */
.jt-tag .value { padding-left: 4px;
}
/* Tag when active */
.jt-tag.active-true { border-color: rgba(82, 168, 236, 0.8);
}
/* Tag remove button ('x') */
.jt-tag .remove-button { cursor: pointer; padding-right: 4px;
}
.jt-tag .remove-button:hover { font-weight: bold;
}
/* New tag input & Edit tag input */
.jt-tag-new, .jt-tag-edit { border: none; outline: 0px; min-width: 50px; /* Will keep autogrow from lowering width more than 60 */
}
/* New tag input & Edit tag input & Tag */
.jt-tag-new, .jt-tag-edit, .jt-tag { margin: 1px 4px 1px 1px;
}
/* Should not be displayed, only used to capture keydown */
.jt-fake-input { float: left; position: absolute; left: -10000px; width: 1px; border: 0px;
}

JsTag - Script Codes JS Codes

angular.module("jsTag", []) .constant("jsTagDefaults", { 'edit': true, 'defaultTags': [], 'breakCodes': [13, 44], 'splitter': ',', 'texts': { 'inputPlaceHolder': 'Input text', 'removeSymbol': String.fromCharCode(215) } }) .run(["$templateCache", function($templateCache){ $templateCache.put("jsTag/source/templates/default/js-tag.html", '<div class="jt-editor" ng-click="inputService.focusInput()" ><span ng-repeat="tag in tagsCollection.tags | toArray:orderBy:\'id\'" ng-switch="tagsCollection.isTagEdited(tag)"> <span ng-switch-when="false" class="jt-tag active-{{tagsCollection.isTagActive(tag)}}"> <span class="value" ng-click="tagsInputService.tagClicked(tag)" ng-dblclick="tagsInputService.tagDblClicked(tag)"> {{tag.value}} </span> <span class="remove-button" ng-click="tagsCollection.removeTag(tag.id)">{{options.texts.removeSymbol}}</span> </span> <span ng-switch-when="true"> <input type="text" class="jt-tag-edit" focus-once ng-model="tag.value" data-tag-id="{{tag.id}}" ng-keydown="inputService.tagInputKeydown(tagsCollection, {$event: $event})" placeholder="{{options.texts.inputPlaceHolder}}" auto-grow /> </span> </span> <input class="jt-tag-new" type="text" focus-me="inputService.isWaitingForInput" ng-model="inputService.input" ng-hide="isThereAnEditedTag" ng-keydown="inputService.onKeydown(inputService, tagsCollection, {$event: $event})" placeholder="{{options.texts.inputPlaceHolder}}" ng-blur="inputService.onBlur(tagsCollection)" auto-grow /> <input class="jt-fake-input" focus-me="isThereAnActiveTag" ng-keydown="tagsInputService.onActiveTagKeydown(inputService, {$event: $event})" ng-blur="tagsInputService.onActiveTagBlur()" /></div>'); }]);
angular.module("jsTag") .filter('inArray', function(){ return function(needle, haystack){ for(var key in haystack){ if(needle === haystack[key]){ return true; } } return false; }; }) .filter('toArray', function(){ return function(input){ var objectsArray = []; for(var key in input){ objectsArray.push(input[key]); } return objectsArray; }; });
angular.module("jsTag") .factory("JSTag", function(){ function JSTag(value, id){ this.value = value; this.id = id; } return JSTag; }) .factory("JSTagsCollection", ['JSTag', '$filter', function(JSTag, $filter){ function JSTagsCollection(defaultTags){ this.tags = {}; this.tagsCounter = 0; for(var defaultTagKey in defaultTags){ var defaultTagValue = defaultTags[defaultTagKey]; this.addTag(defaultTagValue); } this._onAddListenerList = []; this._onRemoveListenerList = []; this.unsetActiveTags(); this.unsetEditedTag(); } //TODO: Object manipulation methods JSTagsCollection.prototype.addTag = function(value) { var tagIndex = this.tagsCounter; this.tagsCounter++; var newTag = new JSTag(value, tagIndex); this.tags[tagIndex] = newTag; angular.forEach(this._onAddListenerList, function (callback) { callback(newTag); }); }; JSTagsCollection.prototype.removeTag = function(tagIndex) { var tag = this.tags[tagIndex]; delete this.tags[tagIndex]; angular.forEach(this._onRemoveListenerList, function (callback) { callback(tag); }); }; JSTagsCollection.prototype.onAdd = function onAdd(callback) { this._onAddListenerList.push(callback); }; JSTagsCollection.prototype.onRemove = function onRemove(callback) { this._onRemoveListenerList.push(callback); }; JSTagsCollection.prototype.getNumberOfTags = function() { return getNumberOfProperties(this.tags); }; JSTagsCollection.prototype.getTagValues = function() { var tagValues = []; for (var tag in this.tags) { tagValues.push(this.tags[tag].value); } return tagValues; }; JSTagsCollection.prototype.getPreviousTag = function(tag) { var firstTag = getFirstProperty(this.tags); if (firstTag.id === tag.id) { // Return same tag if we reached the beginning return tag; } else { return getPreviousProperty(this.tags, tag.id); } }; JSTagsCollection.prototype.getNextTag = function(tag) { var lastTag = getLastProperty(this.tags); if (tag.id === lastTag.id) { // Return same tag if we reached the end return tag; } else { return getNextProperty(this.tags, tag.id); } }; //TODO: Active methods JSTagsCollection.prototype.isTagActive = function(tag) { return $filter("inArray")(tag, this._activeTags); }; JSTagsCollection.prototype.setActiveTag = function(tag) { if (!this.isTagActive(tag)) { this._activeTags.push(tag); } }; JSTagsCollection.prototype.setLastTagActive = function() { if (getNumberOfProperties(this.tags) > 0) { var lastTag = getLastProperty(this.tags); this.setActiveTag(lastTag); } }; JSTagsCollection.prototype.unsetActiveTag = function(tag) { var removedTag = this._activeTags.splice(this._activeTags.indexOf(tag), 1); }; JSTagsCollection.prototype.unsetActiveTags = function() { this._activeTags = []; }; JSTagsCollection.prototype.getActiveTag = function() { var activeTag = null; if (this._activeTags.length === 1) { activeTag = this._activeTags[0]; } return activeTag; }; JSTagsCollection.prototype.getNumOfActiveTags = function() { return this._activeTags.length; }; //TODO: Edit methods JSTagsCollection.prototype.getEditedTag = function() { return this._editedTag; }; JSTagsCollection.prototype.isTagEdited = function(tag) { return tag === this._editedTag; }; JSTagsCollection.prototype.setEditedTag = function(tag) { this._editedTag = tag; }; JSTagsCollection.prototype.unsetEditedTag = function() { // Kill empty tags! if (this._editedTag !== undefined && this._editedTag !== null && this._editedTag.value === "") { this.removeTag(this._editedTag.id); } this._editedTag = null; }; return JSTagsCollection; }]);
angular.module("jsTag") .factory("InputService", ['$filter', function($filter){ function InputService(options){ this.input = ""; this.isWaitingForInput = options.autoFocus || false; this.options = options; } //TODO: Events InputService.prototype.onkeydown = function(inputService, tagsCollection, options){ var e = options.$event; var $element = angular.element(e.currentTarget); var keycode = e.which; var value = ($element.typeahead !== undefined) ? $element.typeahead('val') : this.input; var valueIsEmpty = (value === null || value === undefined || value === ""); if($filter("inArray")(keycode, this.options.breakCodes) !== false){ inputService.breakCodeHit(tagsCollection, this.options); $element.triggerHandler('jsTag:breakcodeHit'); if(!valueIsEmpty){ e.preventDefault(); } }else{ switch (keycode){ case 9: //TAB break; case 37:// Left arrow case 8://Backapace if(valueIsEmpty){ tagsCollection.setLastTagActive(); } break; } } }; InputService.prototype.tagInputKeydown = function(tagsCollection, options){ var e = options.$event; var keycode = e.which; if($filter("inArray")(keycode, this.options.breakCodes) !== false){ this.breakCodeHitOnEdit(tagsCollection, options); } }; InputService.prototype.onBlur = function(tagsCollection) { this.breakCodeHit(tagsCollection, this.options); }; //TODO: Method InputService.prototype.resetInput = function() { var value = this.input; this.input = ""; return value; }; InputService.prototype.focusInput = function() { this.isWaitingForInput = true; }; InputService.prototype.breakCodeHit = function(tagsCollection, options) { if( this.input !== ''){ var originalValue = this.resetInput(); if(originalValue instanceof Object){ originalValue = originalValue[options.tagDisplayKey || Object.keys(originalValue)[0]]; } var values = originalValue.split(options.splitter); for (var i = 0; i < values.length; i++) { if (!values[i]) { values.splice(i, 1); i--; } } for (var key in values) { if ( !values.hasOwnProperty(key) ) continue; // for IE 8 var value = values[key]; tagsCollection.addTag(value); } } }; InputService.prototype.breakCodeHitOnEdit = function(tagsCollection, options) { var editedTag = tagsCollection.getEditedTag(); if (editedTag.value instanceof Object) { editedTag.value = editedTag.value[options.tagDisplayKey || Object.keys(editedTag.value)[0]]; } tagsCollection.unsetEditedTag(); this.isWaitingForInput = true; }; return InputService; }]) .factory("TagsInputService", ['JSTag', 'JSTagsCollection', function(JSTag, JSTagsCollection){ function TagsHandler(options){ this.options = options; var tags = options.tags; if (tags && Object.getPrototypeOf(tags) === JSTagsCollection.prototype) { this.tagsCollection = tags; }else{ var defaultTags = options.defaultTags; this.tagsCollection = new JSTagsCollection(defaultTags); } this.shouldBlurActiveTag = true; } TagsHandler.prototype.tagClicked = function(tag) { this.tagsCollection.setActiveTag(tag); }; TagsHandler.prototype.tagDblClicked = function(tag) { var editAllowed = this.options.edit; if (editAllowed) { this.tagsCollection.setEditedTag(tag); } }; TagsHandler.prototype.onActiveTagKeydown = function(inputService, options) { var activeTag = this.tagsCollection.getActiveTag(); // Do nothing in unexpected situations if (activeTag !== null) { var e = options.$event; // Mimics blur of the active tag though the focus is on the input. // This will cause expected features like unseting active tag var blurActiveTag = function() { // Expose the option not to blur the active tag if (this.shouldBlurActiveTag) { this.onActiveTagBlur(options); } }; switch (e.which) { case 13: // Return var editAllowed = this.options.edit; if (editAllowed) { blurActiveTag.apply(this); this.tagsCollection.setEditedTag(activeTag); } break; case 8: // Backspace this.tagsCollection.removeTag(activeTag.id); inputService.isWaitingForInput = true; break; case 37: // Left arrow blurActiveTag.apply(this); var previousTag = this.tagsCollection.getPreviousTag(activeTag); this.tagsCollection.setActiveTag(previousTag); break; case 39: // Right arrow blurActiveTag.apply(this); var nextTag = this.tagsCollection.getNextTag(activeTag); if (nextTag !== activeTag) { this.tagsCollection.setActiveTag(nextTag); } else { inputService.isWaitingForInput = true; } break; } } }; TagsHandler.prototype.onActiveTagBlur = function(options) { var activeTag = this.tagsCollection.getActiveTag(); // Do nothing in unexpected situations if (activeTag !== null) { this.tagsCollection.unsetActiveTag(activeTag); } }; TagsHandler.prototype.onEditTagBlur = function(tagsCollection, inputService) { tagsCollection.unsetEditedTag(); this.isWaitingForInput = true; } return TagsHandler; }]);
angular.module("jsTag") .controller("JSTagMainCtrl", ['$attrs', '$scope', 'InputService', 'TagsInputService', 'jsTagDefaults', function($attrs, $scope, InputService, TagsInputService, jsTagDefaults){ var userOptions = {}; try { userOptions = $scope.$eval($attrs.jsTagOptions); } catch(e) { console.log("jsTag Error: Invalid user options, using defaults only"); } var options = angular.copy(jsTagDefaults); if (userOptions !== undefined) { userOptions.texts = angular.extend(options.texts, userOptions.texts || {}); angular.extend(options, userOptions); } $scope.options = options; $scope.tagsInputService = new TagsInputService($scope.options); $scope.inputService = new InputService($scope.options); var tagsCollection = $scope.tagsInputService.tagsCollection; $scope.tagsCollection = tagsCollection; $scope.$watch('tagsCollection._editedTag', function(newValue, oldValue) { $scope.isThereAnEditedTag = newValue !== null; }); $scope.$watchCollection('tagsCollection._activeTags', function(newValue, oldValue) { $scope.isThereAnActiveTag = newValue.length > 0; }); } ]);
angular.module("jsTag") .directive("jsTag", ['$templateCache', function($templateCache){ return { restrict: 'E', scope: true, controller: 'JSTagMainCtrl', templateUrl: function($element, $attrs){ var mode = $attrs.jsTagMode || "default"; return 'jsTag/source/templates/' + mode + '/js-tag.html'; } }; }]) .directive("ngBlur", ['$parse', function($parse){ return { restrict: 'A', link: function(scope, elem, attrs){ var functionToCall = $parse(attrs.ngBlur); elem.bind('blur', function(event){ scope.$apply(function(){ functionToCall(scope, {$event: event}); }); }) } }; }]) .directive("focusMe", ['$parse', '$timeout', function($parse, $timeout){ return { restrict: 'A', link: function(scope, element, attrs){ var model = $parse(attrs.focusMe); scope.$watch(model, function(value){ if(value === true){ $timeout(function(){ element[0].focus(); }); } }); element.bind('blur', function(){ scope.$apply(model.assign(scope, false)); }); } }; }]) .directive("focusOnce", ['$timeout', function($timeout){ return { restrict: 'A', link: function(scope, element, attrs){ $timeout(function(){ element[0].select(); }); } }; }]) .directive("autoGrow", ['$timeout', function($timeout){ return { link: function(scope, element, attrs){ var paddingLeft = element.css('paddingLeft'), paddingRight = element.css('paddingRight'); var minWidth = 60; var $shadow = angular.element('<span></span>').css({ 'position': 'absolute', 'top': '-10000px', 'left': '-10000px', 'fontSize': element.css('fontSize'), 'fontFamily': element.css('fontFamily'), 'white-space': 'pre' }); element.after($shadow); function update(){ var val = element.val() .replace(/</g, '&lt;') .replace(/>/g, '&gt;') .replace(/&/g, '&amp;'); if(val !== ""){ $shadow.html(val); }else{ $shadow.html(element[0].placeholder); } var newWidth = ($shadow[0].offsetWidth + 10) + "px"; element.css('width', newWidth); } var ngModel = element.attr('ng-model'); if(ngModel){ scope.$watch(ngModel, update); }else{ element.bind('keyup keydown', update); } $timeout(update); } } }]) .directive("jsTagTypeahead", function(){//预先输入 return { restrict: 'A', require: '?ngModel', link: function(scope, element, attrs, ngModel){ element.bind("jsTag:breakcodeHit", function(event){ if(scope.$eval(attrs.options).contentEditable === false){return;} $(event.currentTarget).typeahead('val', ''); }) } }; });
function getNumberOfProperties(obj) { return Object.keys(obj).length;
}
function getFirstProperty(obj) { var keys = Object.keys(obj); return obj[keys[0]];
}
function getLastProperty(obj) { var keys = Object.keys(obj); return obj[keys[keys.length - 1]];
}
function getNextProperty(obj, propertyId) { var keys = Object.keys(obj); var indexOfProperty = keys.indexOf(propertyId.toString()); var keyOfNextProperty = keys[indexOfProperty + 1]; return obj[keyOfNextProperty];
}
function getPreviousProperty(obj, propertyId) { var keys = Object.keys(obj); var indexOfProperty = keys.indexOf(propertyId.toString()); var keyOfPreviousProperty = keys[indexOfProperty - 1]; return obj[keyOfPreviousProperty];
}
//----------------------------------------------------
//--- 测试代码
//----------------------------------------------------
angular.module("demoJSTag", ['siyfion.sfTypeahead', 'jsTag']);
angular.module("demoJSTag").controller("MoreControlController", MoreControlController);
function MoreControlController($scope, JSTagsCollection){ $scope.tags = new JSTagsCollection(["jsTag", "angularJS"]); $scope.jsTagOptions = { "tags": $scope.tags };
}
MoreControlController.$jection = ['$scope', 'JSTagsCollection'];
/**
angular.module("demoJSTag").controller("CustomizedController", CustomizedController);
angular.module("demoJSTag").controller("NoneditableController", NoneditableController);
angular.module("demoJSTag").controller("TypeaheadController", TypeaheadController);
**/
angular.bootstrap(document, ['demoJSTag']);
JsTag - Script Codes
JsTag - Script Codes
Home Page Home
Developer Kevin
Username chenming142
Uploaded August 28, 2022
Rating 3
Size 7,050 Kb
Views 30,360
Do you need developer help for JsTag?

Find the perfect freelance services for your business! Fiverr's mission is to change how the world works together. Fiverr connects businesses with freelancers offering digital services in 500+ categories. Find Developer!

Kevin (chenming142) Script Codes
Create amazing Facebook ads with AI!

Jasper is the AI Content Generator that helps you and your team break through creative blocks to create amazing, original content 10X faster. Discover all the ways the Jasper AI Content Platform can help streamline your creative workflows. Start For Free!