diff options
Diffstat (limited to 'library')
-rw-r--r-- | library/bootstrap-tagsinput/LICENSE | 20 | ||||
-rw-r--r-- | library/bootstrap-tagsinput/README | 1 | ||||
-rw-r--r-- | library/bootstrap-tagsinput/README.md | 879 | ||||
-rw-r--r-- | library/bootstrap-tagsinput/bootstrap-tagsinput.css | 46 | ||||
-rw-r--r-- | library/bootstrap-tagsinput/bootstrap-tagsinput.js | 643 |
5 files changed, 1589 insertions, 0 deletions
diff --git a/library/bootstrap-tagsinput/LICENSE b/library/bootstrap-tagsinput/LICENSE new file mode 100644 index 000000000..58bc985ba --- /dev/null +++ b/library/bootstrap-tagsinput/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013 Tim Schlechter + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/library/bootstrap-tagsinput/README b/library/bootstrap-tagsinput/README new file mode 100644 index 000000000..a7c96d53a --- /dev/null +++ b/library/bootstrap-tagsinput/README @@ -0,0 +1 @@ +Taken from https://github.com/gdibble/bootstrap-tagsinput/tree/traditionalPlaceholderEffect which has proper support for placeholders diff --git a/library/bootstrap-tagsinput/README.md b/library/bootstrap-tagsinput/README.md new file mode 100644 index 000000000..363c0d50b --- /dev/null +++ b/library/bootstrap-tagsinput/README.md @@ -0,0 +1,879 @@ + + + + +<!DOCTYPE html> +<html lang="en" class=""> + <head prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# object: http://ogp.me/ns/object# article: http://ogp.me/ns/article# profile: http://ogp.me/ns/profile#"> + <meta charset='utf-8'> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <meta http-equiv="Content-Language" content="en"> + + + <title>bootstrap-tagsinput/README.md at master · TimSchlechter/bootstrap-tagsinput · GitHub</title> + <link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="GitHub"> + <link rel="fluid-icon" href="https://github.com/fluidicon.png" title="GitHub"> + <link rel="apple-touch-icon" sizes="57x57" href="/apple-touch-icon-114.png"> + <link rel="apple-touch-icon" sizes="114x114" href="/apple-touch-icon-114.png"> + <link rel="apple-touch-icon" sizes="72x72" href="/apple-touch-icon-144.png"> + <link rel="apple-touch-icon" sizes="144x144" href="/apple-touch-icon-144.png"> + <meta property="fb:app_id" content="1401488693436528"> + + <meta content="@github" name="twitter:site" /><meta content="summary" name="twitter:card" /><meta content="TimSchlechter/bootstrap-tagsinput" name="twitter:title" /><meta content="bootstrap-tagsinput - jQuery tags input plugin based on Twitter Bootstrap." name="twitter:description" /><meta content="https://avatars1.githubusercontent.com/u/2721613?v=3&s=400" name="twitter:image:src" /> +<meta content="GitHub" property="og:site_name" /><meta content="object" property="og:type" /><meta content="https://avatars1.githubusercontent.com/u/2721613?v=3&s=400" property="og:image" /><meta content="TimSchlechter/bootstrap-tagsinput" property="og:title" /><meta content="https://github.com/TimSchlechter/bootstrap-tagsinput" property="og:url" /><meta content="bootstrap-tagsinput - jQuery tags input plugin based on Twitter Bootstrap." property="og:description" /> + + <meta name="browser-stats-url" content="/_stats"> + <link rel="assets" href="https://assets-cdn.github.com/"> + <link rel="conduit-xhr" href="https://ghconduit.com:25035"> + + <meta name="pjax-timeout" content="1000"> + + + <meta name="msapplication-TileImage" content="/windows-tile.png"> + <meta name="msapplication-TileColor" content="#ffffff"> + <meta name="selected-link" value="repo_source" data-pjax-transient> + <meta name="google-analytics" content="UA-3769691-2"> + + <meta content="collector.githubapp.com" name="octolytics-host" /><meta content="collector-cdn.github.com" name="octolytics-script-host" /><meta content="github" name="octolytics-app-id" /><meta content="05C412F3:5EFA:620CC:54968B9C" name="octolytics-dimension-request_id" /> + + <meta content="Rails, view, blob#show" name="analytics-event" /> + + + + <link rel="icon" type="image/x-icon" href="https://assets-cdn.github.com/favicon.ico"> + + + <meta content="authenticity_token" name="csrf-param" /> +<meta content="pq46YRAN8EIxwiqw1PBmOS18o8ukCrBKyIwYs6EhhTJPiGbEXhKdJxdkbRWl+VYne3E3iSUijxSIsYnZnQddlg==" name="csrf-token" /> + + <link href="https://assets-cdn.github.com/assets/github-9bcf5def7eb44e2a101b20aaecf3707f4b0a10ab8f4d6eebec29371f821c4b29.css" media="all" rel="stylesheet" type="text/css" /> + <link href="https://assets-cdn.github.com/assets/github2-47bc67324d463c7cecb5ee4c009628c91db85b0e9288a9e663f2d06ff9e03088.css" media="all" rel="stylesheet" type="text/css" /> + + + + + <meta http-equiv="x-pjax-version" content="cffc32e08a29062b908cc3ddb47285af"> + + + <meta name="description" content="bootstrap-tagsinput - jQuery tags input plugin based on Twitter Bootstrap."> + <meta name="go-import" content="github.com/TimSchlechter/bootstrap-tagsinput git https://github.com/TimSchlechter/bootstrap-tagsinput.git"> + + <meta content="2721613" name="octolytics-dimension-user_id" /><meta content="TimSchlechter" name="octolytics-dimension-user_login" /><meta content="11534941" name="octolytics-dimension-repository_id" /><meta content="TimSchlechter/bootstrap-tagsinput" name="octolytics-dimension-repository_nwo" /><meta content="true" name="octolytics-dimension-repository_public" /><meta content="false" name="octolytics-dimension-repository_is_fork" /><meta content="11534941" name="octolytics-dimension-repository_network_root_id" /><meta content="TimSchlechter/bootstrap-tagsinput" name="octolytics-dimension-repository_network_root_nwo" /> + <link href="https://github.com/TimSchlechter/bootstrap-tagsinput/commits/master.atom" rel="alternate" title="Recent Commits to bootstrap-tagsinput:master" type="application/atom+xml"> + + </head> + + + <body class="logged_out env-production vis-public page-blob"> + <a href="#start-of-content" tabindex="1" class="accessibility-aid js-skip-to-content">Skip to content</a> + <div class="wrapper"> + + + + + + + + <div class="header header-logged-out" role="banner"> + <div class="container clearfix"> + + <a class="header-logo-wordmark" href="https://github.com/" ga-data-click="(Logged out) Header, go to homepage, icon:logo-wordmark"> + <span class="mega-octicon octicon-logo-github"></span> + </a> + + <div class="header-actions" role="navigation"> + <a class="button primary" href="/join" data-ga-click="(Logged out) Header, clicked Sign up, text:sign-up">Sign up</a> + <a class="button" href="/login?return_to=%2FTimSchlechter%2Fbootstrap-tagsinput%2Fblob%2Fmaster%2FREADME.md" data-ga-click="(Logged out) Header, clicked Sign in, text:sign-in">Sign in</a> + </div> + + <div class="site-search repo-scope js-site-search" role="search"> + <form accept-charset="UTF-8" action="/TimSchlechter/bootstrap-tagsinput/search" class="js-site-search-form" data-global-search-url="/search" data-repo-search-url="/TimSchlechter/bootstrap-tagsinput/search" method="get"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓" /></div> + <input type="text" + class="js-site-search-field is-clearable" + data-hotkey="s" + name="q" + placeholder="Search" + data-global-scope-placeholder="Search GitHub" + data-repo-scope-placeholder="Search" + tabindex="1" + autocapitalize="off"> + <div class="scope-badge">This repository</div> +</form> + </div> + + <ul class="header-nav left" role="navigation"> + <li class="header-nav-item"> + <a class="header-nav-link" href="/explore" data-ga-click="(Logged out) Header, go to explore, text:explore">Explore</a> + </li> + <li class="header-nav-item"> + <a class="header-nav-link" href="/features" data-ga-click="(Logged out) Header, go to features, text:features">Features</a> + </li> + <li class="header-nav-item"> + <a class="header-nav-link" href="https://enterprise.github.com/" data-ga-click="(Logged out) Header, go to enterprise, text:enterprise">Enterprise</a> + </li> + <li class="header-nav-item"> + <a class="header-nav-link" href="/blog" data-ga-click="(Logged out) Header, go to blog, text:blog">Blog</a> + </li> + </ul> + + </div> +</div> + + + + <div id="start-of-content" class="accessibility-aid"></div> + <div class="site" itemscope itemtype="http://schema.org/WebPage"> + <div id="js-flash-container"> + + </div> + <div class="pagehead repohead instapaper_ignore readability-menu"> + <div class="container"> + +<ul class="pagehead-actions"> + + + <li> + <a href="/login?return_to=%2FTimSchlechter%2Fbootstrap-tagsinput" + class="minibutton with-count star-button tooltipped tooltipped-n" + aria-label="You must be signed in to star a repository" rel="nofollow"> + <span class="octicon octicon-star"></span> + Star + </a> + + <a class="social-count js-social-count" href="/TimSchlechter/bootstrap-tagsinput/stargazers"> + 755 + </a> + + </li> + + <li> + <a href="/login?return_to=%2FTimSchlechter%2Fbootstrap-tagsinput" + class="minibutton with-count js-toggler-target fork-button tooltipped tooltipped-n" + aria-label="You must be signed in to fork a repository" rel="nofollow"> + <span class="octicon octicon-repo-forked"></span> + Fork + </a> + <a href="/TimSchlechter/bootstrap-tagsinput/network" class="social-count"> + 307 + </a> + </li> +</ul> + + <h1 itemscope itemtype="http://data-vocabulary.org/Breadcrumb" class="entry-title public"> + <span class="mega-octicon octicon-repo"></span> + <span class="author"><a href="/TimSchlechter" class="url fn" itemprop="url" rel="author"><span itemprop="title">TimSchlechter</span></a></span><!-- + --><span class="path-divider">/</span><!-- + --><strong><a href="/TimSchlechter/bootstrap-tagsinput" class="js-current-repository" data-pjax="#js-repo-pjax-container">bootstrap-tagsinput</a></strong> + + <span class="page-context-loader"> + <img alt="" height="16" src="https://assets-cdn.github.com/images/spinners/octocat-spinner-32.gif" width="16" /> + </span> + + </h1> + </div><!-- /.container --> + </div><!-- /.repohead --> + + <div class="container"> + <div class="repository-with-sidebar repo-container new-discussion-timeline "> + <div class="repository-sidebar clearfix"> + +<nav class="sunken-menu repo-nav js-repo-nav js-sidenav-container-pjax js-octicon-loaders" + role="navigation" + data-pjax="#js-repo-pjax-container" + data-issue-count-url="/TimSchlechter/bootstrap-tagsinput/issues/counts"> + <ul class="sunken-menu-group"> + <li class="tooltipped tooltipped-w" aria-label="Code"> + <a href="/TimSchlechter/bootstrap-tagsinput" aria-label="Code" class="selected js-selected-navigation-item sunken-menu-item" data-hotkey="g c" data-selected-links="repo_source repo_downloads repo_commits repo_releases repo_tags repo_branches /TimSchlechter/bootstrap-tagsinput"> + <span class="octicon octicon-code"></span> <span class="full-word">Code</span> + <img alt="" class="mini-loader" height="16" src="https://assets-cdn.github.com/images/spinners/octocat-spinner-32.gif" width="16" /> +</a> </li> + + <li class="tooltipped tooltipped-w" aria-label="Issues"> + <a href="/TimSchlechter/bootstrap-tagsinput/issues" aria-label="Issues" class="js-selected-navigation-item sunken-menu-item" data-hotkey="g i" data-selected-links="repo_issues repo_labels repo_milestones /TimSchlechter/bootstrap-tagsinput/issues"> + <span class="octicon octicon-issue-opened"></span> <span class="full-word">Issues</span> + <span class="js-issue-replace-counter"></span> + <img alt="" class="mini-loader" height="16" src="https://assets-cdn.github.com/images/spinners/octocat-spinner-32.gif" width="16" /> +</a> </li> + + <li class="tooltipped tooltipped-w" aria-label="Pull Requests"> + <a href="/TimSchlechter/bootstrap-tagsinput/pulls" aria-label="Pull Requests" class="js-selected-navigation-item sunken-menu-item" data-hotkey="g p" data-selected-links="repo_pulls /TimSchlechter/bootstrap-tagsinput/pulls"> + <span class="octicon octicon-git-pull-request"></span> <span class="full-word">Pull Requests</span> + <span class="js-pull-replace-counter"></span> + <img alt="" class="mini-loader" height="16" src="https://assets-cdn.github.com/images/spinners/octocat-spinner-32.gif" width="16" /> +</a> </li> + + + </ul> + <div class="sunken-menu-separator"></div> + <ul class="sunken-menu-group"> + + <li class="tooltipped tooltipped-w" aria-label="Pulse"> + <a href="/TimSchlechter/bootstrap-tagsinput/pulse" aria-label="Pulse" class="js-selected-navigation-item sunken-menu-item" data-selected-links="pulse /TimSchlechter/bootstrap-tagsinput/pulse"> + <span class="octicon octicon-pulse"></span> <span class="full-word">Pulse</span> + <img alt="" class="mini-loader" height="16" src="https://assets-cdn.github.com/images/spinners/octocat-spinner-32.gif" width="16" /> +</a> </li> + + <li class="tooltipped tooltipped-w" aria-label="Graphs"> + <a href="/TimSchlechter/bootstrap-tagsinput/graphs" aria-label="Graphs" class="js-selected-navigation-item sunken-menu-item" data-selected-links="repo_graphs repo_contributors /TimSchlechter/bootstrap-tagsinput/graphs"> + <span class="octicon octicon-graph"></span> <span class="full-word">Graphs</span> + <img alt="" class="mini-loader" height="16" src="https://assets-cdn.github.com/images/spinners/octocat-spinner-32.gif" width="16" /> +</a> </li> + </ul> + + +</nav> + + <div class="only-with-full-nav"> + + +<div class="clone-url open" + data-protocol-type="http" + data-url="/users/set_protocol?protocol_selector=http&protocol_type=clone"> + <h3><span class="text-emphasized">HTTPS</span> clone URL</h3> + <div class="input-group js-zeroclipboard-container"> + <input type="text" class="input-mini input-monospace js-url-field js-zeroclipboard-target" + value="https://github.com/TimSchlechter/bootstrap-tagsinput.git" readonly="readonly"> + <span class="input-group-button"> + <button aria-label="Copy to clipboard" class="js-zeroclipboard minibutton zeroclipboard-button" data-copied-hint="Copied!" type="button"><span class="octicon octicon-clippy"></span></button> + </span> + </div> +</div> + + +<div class="clone-url " + data-protocol-type="subversion" + data-url="/users/set_protocol?protocol_selector=subversion&protocol_type=clone"> + <h3><span class="text-emphasized">Subversion</span> checkout URL</h3> + <div class="input-group js-zeroclipboard-container"> + <input type="text" class="input-mini input-monospace js-url-field js-zeroclipboard-target" + value="https://github.com/TimSchlechter/bootstrap-tagsinput" readonly="readonly"> + <span class="input-group-button"> + <button aria-label="Copy to clipboard" class="js-zeroclipboard minibutton zeroclipboard-button" data-copied-hint="Copied!" type="button"><span class="octicon octicon-clippy"></span></button> + </span> + </div> +</div> + + + +<p class="clone-options">You can clone with + <a href="#" class="js-clone-selector" data-protocol="http">HTTPS</a> or <a href="#" class="js-clone-selector" data-protocol="subversion">Subversion</a>. + <a href="https://help.github.com/articles/which-remote-url-should-i-use" class="help tooltipped tooltipped-n" aria-label="Get help on which URL is right for you."> + <span class="octicon octicon-question"></span> + </a> +</p> + + + + <a href="/TimSchlechter/bootstrap-tagsinput/archive/master.zip" + class="minibutton sidebar-button" + aria-label="Download the contents of TimSchlechter/bootstrap-tagsinput as a zip file" + title="Download the contents of TimSchlechter/bootstrap-tagsinput as a zip file" + rel="nofollow"> + <span class="octicon octicon-cloud-download"></span> + Download ZIP + </a> + </div> + </div><!-- /.repository-sidebar --> + + <div id="js-repo-pjax-container" class="repository-content context-loader-container" data-pjax-container> + + +<a href="/TimSchlechter/bootstrap-tagsinput/blob/a4657365808a224fe8aa950c14b96ecfce58b290/README.md" class="hidden js-permalink-shortcut" data-hotkey="y">Permalink</a> + +<!-- blob contrib key: blob_contributors:v21:002463f2fb860593a8410f2c5c54cd3a --> + +<div class="file-navigation js-zeroclipboard-container"> + +<div class="select-menu js-menu-container js-select-menu left"> + <span class="minibutton select-menu-button js-menu-target css-truncate" data-hotkey="w" + data-master-branch="master" + data-ref="master" + title="master" + role="button" aria-label="Switch branches or tags" tabindex="0" aria-haspopup="true"> + <span class="octicon octicon-git-branch"></span> + <i>branch:</i> + <span class="js-select-button css-truncate-target">master</span> + </span> + + <div class="select-menu-modal-holder js-menu-content js-navigation-container" data-pjax aria-hidden="true"> + + <div class="select-menu-modal"> + <div class="select-menu-header"> + <span class="select-menu-title">Switch branches/tags</span> + <span class="octicon octicon-x js-menu-close" role="button" aria-label="Close"></span> + </div> <!-- /.select-menu-header --> + + <div class="select-menu-filters"> + <div class="select-menu-text-filter"> + <input type="text" aria-label="Filter branches/tags" id="context-commitish-filter-field" class="js-filterable-field js-navigation-enable" placeholder="Filter branches/tags"> + </div> + <div class="select-menu-tabs"> + <ul> + <li class="select-menu-tab"> + <a href="#" data-tab-filter="branches" class="js-select-menu-tab">Branches</a> + </li> + <li class="select-menu-tab"> + <a href="#" data-tab-filter="tags" class="js-select-menu-tab">Tags</a> + </li> + </ul> + </div><!-- /.select-menu-tabs --> + </div><!-- /.select-menu-filters --> + + <div class="select-menu-list select-menu-tab-bucket js-select-menu-tab-bucket" data-tab-filter="branches"> + + <div data-filterable-for="context-commitish-filter-field" data-filterable-type="substring"> + + + <div class="select-menu-item js-navigation-item "> + <span class="select-menu-item-icon octicon octicon-check"></span> + <a href="/TimSchlechter/bootstrap-tagsinput/blob/gh-pages/README.md" + data-name="gh-pages" + data-skip-pjax="true" + rel="nofollow" + class="js-navigation-open select-menu-item-text css-truncate-target" + title="gh-pages">gh-pages</a> + </div> <!-- /.select-menu-item --> + <div class="select-menu-item js-navigation-item selected"> + <span class="select-menu-item-icon octicon octicon-check"></span> + <a href="/TimSchlechter/bootstrap-tagsinput/blob/master/README.md" + data-name="master" + data-skip-pjax="true" + rel="nofollow" + class="js-navigation-open select-menu-item-text css-truncate-target" + title="master">master</a> + </div> <!-- /.select-menu-item --> + </div> + + <div class="select-menu-no-results">Nothing to show</div> + </div> <!-- /.select-menu-list --> + + <div class="select-menu-list select-menu-tab-bucket js-select-menu-tab-bucket" data-tab-filter="tags"> + <div data-filterable-for="context-commitish-filter-field" data-filterable-type="substring"> + + + <div class="select-menu-item js-navigation-item "> + <span class="select-menu-item-icon octicon octicon-check"></span> + <a href="/TimSchlechter/bootstrap-tagsinput/tree/0.4.2/README.md" + data-name="0.4.2" + data-skip-pjax="true" + rel="nofollow" + class="js-navigation-open select-menu-item-text css-truncate-target" + title="0.4.2">0.4.2</a> + </div> <!-- /.select-menu-item --> + <div class="select-menu-item js-navigation-item "> + <span class="select-menu-item-icon octicon octicon-check"></span> + <a href="/TimSchlechter/bootstrap-tagsinput/tree/0.4.1/README.md" + data-name="0.4.1" + data-skip-pjax="true" + rel="nofollow" + class="js-navigation-open select-menu-item-text css-truncate-target" + title="0.4.1">0.4.1</a> + </div> <!-- /.select-menu-item --> + <div class="select-menu-item js-navigation-item "> + <span class="select-menu-item-icon octicon octicon-check"></span> + <a href="/TimSchlechter/bootstrap-tagsinput/tree/0.4/README.md" + data-name="0.4" + data-skip-pjax="true" + rel="nofollow" + class="js-navigation-open select-menu-item-text css-truncate-target" + title="0.4">0.4</a> + </div> <!-- /.select-menu-item --> + <div class="select-menu-item js-navigation-item "> + <span class="select-menu-item-icon octicon octicon-check"></span> + <a href="/TimSchlechter/bootstrap-tagsinput/tree/0.3.14/README.md" + data-name="0.3.14" + data-skip-pjax="true" + rel="nofollow" + class="js-navigation-open select-menu-item-text css-truncate-target" + title="0.3.14">0.3.14</a> + </div> <!-- /.select-menu-item --> + <div class="select-menu-item js-navigation-item "> + <span class="select-menu-item-icon octicon octicon-check"></span> + <a href="/TimSchlechter/bootstrap-tagsinput/tree/0.3.13/README.md" + data-name="0.3.13" + data-skip-pjax="true" + rel="nofollow" + class="js-navigation-open select-menu-item-text css-truncate-target" + title="0.3.13">0.3.13</a> + </div> <!-- /.select-menu-item --> + <div class="select-menu-item js-navigation-item "> + <span class="select-menu-item-icon octicon octicon-check"></span> + <a href="/TimSchlechter/bootstrap-tagsinput/tree/0.3.12/README.md" + data-name="0.3.12" + data-skip-pjax="true" + rel="nofollow" + class="js-navigation-open select-menu-item-text css-truncate-target" + title="0.3.12">0.3.12</a> + </div> <!-- /.select-menu-item --> + <div class="select-menu-item js-navigation-item "> + <span class="select-menu-item-icon octicon octicon-check"></span> + <a href="/TimSchlechter/bootstrap-tagsinput/tree/0.3.11/README.md" + data-name="0.3.11" + data-skip-pjax="true" + rel="nofollow" + class="js-navigation-open select-menu-item-text css-truncate-target" + title="0.3.11">0.3.11</a> + </div> <!-- /.select-menu-item --> + <div class="select-menu-item js-navigation-item "> + <span class="select-menu-item-icon octicon octicon-check"></span> + <a href="/TimSchlechter/bootstrap-tagsinput/tree/0.3.10/README.md" + data-name="0.3.10" + data-skip-pjax="true" + rel="nofollow" + class="js-navigation-open select-menu-item-text css-truncate-target" + title="0.3.10">0.3.10</a> + </div> <!-- /.select-menu-item --> + <div class="select-menu-item js-navigation-item "> + <span class="select-menu-item-icon octicon octicon-check"></span> + <a href="/TimSchlechter/bootstrap-tagsinput/tree/0.3.9/README.md" + data-name="0.3.9" + data-skip-pjax="true" + rel="nofollow" + class="js-navigation-open select-menu-item-text css-truncate-target" + title="0.3.9">0.3.9</a> + </div> <!-- /.select-menu-item --> + <div class="select-menu-item js-navigation-item "> + <span class="select-menu-item-icon octicon octicon-check"></span> + <a href="/TimSchlechter/bootstrap-tagsinput/tree/0.3.8/README.md" + data-name="0.3.8" + data-skip-pjax="true" + rel="nofollow" + class="js-navigation-open select-menu-item-text css-truncate-target" + title="0.3.8">0.3.8</a> + </div> <!-- /.select-menu-item --> + <div class="select-menu-item js-navigation-item "> + <span class="select-menu-item-icon octicon octicon-check"></span> + <a href="/TimSchlechter/bootstrap-tagsinput/tree/0.3.7/README.md" + data-name="0.3.7" + data-skip-pjax="true" + rel="nofollow" + class="js-navigation-open select-menu-item-text css-truncate-target" + title="0.3.7">0.3.7</a> + </div> <!-- /.select-menu-item --> + <div class="select-menu-item js-navigation-item "> + <span class="select-menu-item-icon octicon octicon-check"></span> + <a href="/TimSchlechter/bootstrap-tagsinput/tree/0.3.6/README.md" + data-name="0.3.6" + data-skip-pjax="true" + rel="nofollow" + class="js-navigation-open select-menu-item-text css-truncate-target" + title="0.3.6">0.3.6</a> + </div> <!-- /.select-menu-item --> + <div class="select-menu-item js-navigation-item "> + <span class="select-menu-item-icon octicon octicon-check"></span> + <a href="/TimSchlechter/bootstrap-tagsinput/tree/0.3.5/README.md" + data-name="0.3.5" + data-skip-pjax="true" + rel="nofollow" + class="js-navigation-open select-menu-item-text css-truncate-target" + title="0.3.5">0.3.5</a> + </div> <!-- /.select-menu-item --> + <div class="select-menu-item js-navigation-item "> + <span class="select-menu-item-icon octicon octicon-check"></span> + <a href="/TimSchlechter/bootstrap-tagsinput/tree/0.3.4/README.md" + data-name="0.3.4" + data-skip-pjax="true" + rel="nofollow" + class="js-navigation-open select-menu-item-text css-truncate-target" + title="0.3.4">0.3.4</a> + </div> <!-- /.select-menu-item --> + <div class="select-menu-item js-navigation-item "> + <span class="select-menu-item-icon octicon octicon-check"></span> + <a href="/TimSchlechter/bootstrap-tagsinput/tree/0.3.3/README.md" + data-name="0.3.3" + data-skip-pjax="true" + rel="nofollow" + class="js-navigation-open select-menu-item-text css-truncate-target" + title="0.3.3">0.3.3</a> + </div> <!-- /.select-menu-item --> + <div class="select-menu-item js-navigation-item "> + <span class="select-menu-item-icon octicon octicon-check"></span> + <a href="/TimSchlechter/bootstrap-tagsinput/tree/0.3.2/README.md" + data-name="0.3.2" + data-skip-pjax="true" + rel="nofollow" + class="js-navigation-open select-menu-item-text css-truncate-target" + title="0.3.2">0.3.2</a> + </div> <!-- /.select-menu-item --> + <div class="select-menu-item js-navigation-item "> + <span class="select-menu-item-icon octicon octicon-check"></span> + <a href="/TimSchlechter/bootstrap-tagsinput/tree/0.3.1/README.md" + data-name="0.3.1" + data-skip-pjax="true" + rel="nofollow" + class="js-navigation-open select-menu-item-text css-truncate-target" + title="0.3.1">0.3.1</a> + </div> <!-- /.select-menu-item --> + <div class="select-menu-item js-navigation-item "> + <span class="select-menu-item-icon octicon octicon-check"></span> + <a href="/TimSchlechter/bootstrap-tagsinput/tree/0.3.0/README.md" + data-name="0.3.0" + data-skip-pjax="true" + rel="nofollow" + class="js-navigation-open select-menu-item-text css-truncate-target" + title="0.3.0">0.3.0</a> + </div> <!-- /.select-menu-item --> + <div class="select-menu-item js-navigation-item "> + <span class="select-menu-item-icon octicon octicon-check"></span> + <a href="/TimSchlechter/bootstrap-tagsinput/tree/0.2.3/README.md" + data-name="0.2.3" + data-skip-pjax="true" + rel="nofollow" + class="js-navigation-open select-menu-item-text css-truncate-target" + title="0.2.3">0.2.3</a> + </div> <!-- /.select-menu-item --> + <div class="select-menu-item js-navigation-item "> + <span class="select-menu-item-icon octicon octicon-check"></span> + <a href="/TimSchlechter/bootstrap-tagsinput/tree/0.2.2/README.md" + data-name="0.2.2" + data-skip-pjax="true" + rel="nofollow" + class="js-navigation-open select-menu-item-text css-truncate-target" + title="0.2.2">0.2.2</a> + </div> <!-- /.select-menu-item --> + <div class="select-menu-item js-navigation-item "> + <span class="select-menu-item-icon octicon octicon-check"></span> + <a href="/TimSchlechter/bootstrap-tagsinput/tree/0.2.1/README.md" + data-name="0.2.1" + data-skip-pjax="true" + rel="nofollow" + class="js-navigation-open select-menu-item-text css-truncate-target" + title="0.2.1">0.2.1</a> + </div> <!-- /.select-menu-item --> + <div class="select-menu-item js-navigation-item "> + <span class="select-menu-item-icon octicon octicon-check"></span> + <a href="/TimSchlechter/bootstrap-tagsinput/tree/0.2.0/README.md" + data-name="0.2.0" + data-skip-pjax="true" + rel="nofollow" + class="js-navigation-open select-menu-item-text css-truncate-target" + title="0.2.0">0.2.0</a> + </div> <!-- /.select-menu-item --> + <div class="select-menu-item js-navigation-item "> + <span class="select-menu-item-icon octicon octicon-check"></span> + <a href="/TimSchlechter/bootstrap-tagsinput/tree/0.1.1/README.md" + data-name="0.1.1" + data-skip-pjax="true" + rel="nofollow" + class="js-navigation-open select-menu-item-text css-truncate-target" + title="0.1.1">0.1.1</a> + </div> <!-- /.select-menu-item --> + <div class="select-menu-item js-navigation-item "> + <span class="select-menu-item-icon octicon octicon-check"></span> + <a href="/TimSchlechter/bootstrap-tagsinput/tree/0.1.0/README.md" + data-name="0.1.0" + data-skip-pjax="true" + rel="nofollow" + class="js-navigation-open select-menu-item-text css-truncate-target" + title="0.1.0">0.1.0</a> + </div> <!-- /.select-menu-item --> + </div> + + <div class="select-menu-no-results">Nothing to show</div> + </div> <!-- /.select-menu-list --> + + </div> <!-- /.select-menu-modal --> + </div> <!-- /.select-menu-modal-holder --> +</div> <!-- /.select-menu --> + + <div class="button-group right"> + <a href="/TimSchlechter/bootstrap-tagsinput/find/master" + class="js-show-file-finder minibutton empty-icon tooltipped tooltipped-s" + data-pjax + data-hotkey="t" + aria-label="Quickly jump between files"> + <span class="octicon octicon-list-unordered"></span> + </a> + <button aria-label="Copy file path to clipboard" class="js-zeroclipboard minibutton zeroclipboard-button" data-copied-hint="Copied!" type="button"><span class="octicon octicon-clippy"></span></button> + </div> + + <div class="breadcrumb js-zeroclipboard-target"> + <span class='repo-root js-repo-root'><span itemscope="" itemtype="http://data-vocabulary.org/Breadcrumb"><a href="/TimSchlechter/bootstrap-tagsinput" class="" data-branch="master" data-direction="back" data-pjax="true" itemscope="url"><span itemprop="title">bootstrap-tagsinput</span></a></span></span><span class="separator">/</span><strong class="final-path">README.md</strong> + </div> +</div> + + + <div class="commit file-history-tease"> + <div class="file-history-tease-header"> + <img alt="Tim Schlechter" class="avatar" data-user="2721613" height="24" src="https://avatars3.githubusercontent.com/u/2721613?v=3&s=48" width="24" /> + <span class="author"><a href="/TimSchlechter" rel="author">TimSchlechter</a></span> + <time datetime="2014-07-30T18:40:53Z" is="relative-time">Jul 30, 2014</time> + <div class="commit-title"> + <a href="/TimSchlechter/bootstrap-tagsinput/commit/a64536d346d252a6fb5d013a53ff0b6a6a991ba8" class="message" data-pjax="true" title="Release build 0.4">Release build 0.4</a> + </div> + </div> + + <div class="participation"> + <p class="quickstat"> + <a href="#blob_contributors_box" rel="facebox"> + <strong>1</strong> + contributor + </a> + </p> + + </div> + <div id="blob_contributors_box" style="display:none"> + <h2 class="facebox-header">Users who have contributed to this file</h2> + <ul class="facebox-user-list"> + <li class="facebox-user-list-item"> + <img alt="Tim Schlechter" data-user="2721613" height="24" src="https://avatars3.githubusercontent.com/u/2721613?v=3&s=48" width="24" /> + <a href="/TimSchlechter">TimSchlechter</a> + </li> + </ul> + </div> + </div> + +<div class="file-box"> + <div class="file"> + <div class="meta clearfix"> + <div class="info file-name"> + <span>70 lines (61 sloc)</span> + <span class="meta-divider"></span> + <span>3.157 kb</span> + </div> + <div class="actions"> + <div class="button-group"> + <a href="/TimSchlechter/bootstrap-tagsinput/raw/master/README.md" class="minibutton " id="raw-url">Raw</a> + <a href="/TimSchlechter/bootstrap-tagsinput/blame/master/README.md" class="minibutton js-update-url-with-hash">Blame</a> + <a href="/TimSchlechter/bootstrap-tagsinput/commits/master/README.md" class="minibutton " rel="nofollow">History</a> + </div><!-- /.button-group --> + + + <a class="octicon-button disabled tooltipped tooltipped-w" href="#" + aria-label="You must be signed in to make or propose changes"><span class="octicon octicon-pencil"></span></a> + + <a class="octicon-button danger disabled tooltipped tooltipped-w" href="#" + aria-label="You must be signed in to make or propose changes"> + <span class="octicon octicon-trashcan"></span> + </a> + </div><!-- /.actions --> + </div> + + <div id="readme" class="blob instapaper_body"> + <article class="markdown-body entry-content" itemprop="mainContentOfPage"><h1> +<a id="user-content-bootstrap-tags-input-" class="anchor" href="#bootstrap-tags-input-" aria-hidden="true"><span class="octicon octicon-link"></span></a>Bootstrap Tags Input <a href="https://travis-ci.org/TimSchlechter/bootstrap-tagsinput"><img src="https://camo.githubusercontent.com/2d02546931244241329b98071825212a0d77dd4e/68747470733a2f2f7472617669732d63692e6f72672f54696d5363686c6563687465722f626f6f7473747261702d74616773696e7075742e7376673f6272616e63683d6d6173746572" alt="Build Status" data-canonical-src="https://travis-ci.org/TimSchlechter/bootstrap-tagsinput.svg?branch=master" style="max-width:100%;"></a> +</h1> + +<p>Bootstrap Tags Input is a jQuery plugin providing a Twitter Bootstrap user interface for managing tags.</p> + +<h2> +<a id="user-content-usage" class="anchor" href="#usage" aria-hidden="true"><span class="octicon octicon-link"></span></a>Usage</h2> + +<p>Examples can be found <a href="http://timschlechter.github.com/bootstrap-tagsinput/examples/">here</a>.</p> + +<h2> +<a id="user-content-features" class="anchor" href="#features" aria-hidden="true"><span class="octicon octicon-link"></span></a>Features</h2> + +<ul class="task-list"> +<li>Objects as tags</li> +<li>True multi value</li> +<li>Typeahead</li> +<li>Designed for Bootstrap 2.3.2 and 3</li> +</ul> + +<h3> +<a id="user-content-objects-as-tags" class="anchor" href="#objects-as-tags" aria-hidden="true"><span class="octicon octicon-link"></span></a>Objects as tags</h3> + +<p>Not just support for using strings! This means you can use different values +for a tag's label and value. Each tag also holds a reference to the object +by which it was created, so by calling <code>tagsinput('items')</code> an +array of the original items is returned.</p> + +<h3> +<a id="user-content-true-multi-value-support" class="anchor" href="#true-multi-value-support" aria-hidden="true"><span class="octicon octicon-link"></span></a>True multi value support</h3> + +<p>Other implementations just concatenate the values to a comma separated string. +This results in <code>val()</code> returning just this string, and when +submitting the form, only one big, concatenated value is sent in the request.</p> + +<p>Bootstrap Tags Input provides true multivalue support. Just use a +<code><select multiple /></code> as your input element, and +<code>val()</code> will return an array of the tag values. When submitting the +form, an array of values will be sent with the request.</p> + +<h3> +<a id="user-content-typeahead-support" class="anchor" href="#typeahead-support" aria-hidden="true"><span class="octicon octicon-link"></span></a>Typeahead support</h3> + +<p>Integrates with Twitter Bootstraps' 2.3.2 typeahead, or use custom typeahead when using Bootstrap 3.</p> + +<h2> +<a id="user-content-development" class="anchor" href="#development" aria-hidden="true"><span class="octicon octicon-link"></span></a>Development</h2> + +<p>Install dependencies:</p> + +<pre> +npm install +bower install +</pre> + +<p>Test:</p> + +<pre> +grunt test +</pre> + +<p>Build:</p> + +<pre> +grunt build +</pre> + +<h2> +<a id="user-content-history" class="anchor" href="#history" aria-hidden="true"><span class="octicon octicon-link"></span></a>History</h2> + +<ul class="task-list"> +<li>0.4 + +<ul class="task-list"> +<li><a href="https://github.com/TimSchlechter/bootstrap-tagsinput/pull/73">Fix typeahead when using Bootstrap 3</a></li> +</ul> +</li> +<li>0.3.13 + +<ul class="task-list"> +<li> <a href="https://github.com/TimSchlechter/bootstrap-tagsinput/issues/5">#5: Trigger events on original input/select</a> +</li> +<li> Loads of fixes merged with help of @janvt, @rlidwka and @kuraga: thanks for helping me out!</li> +</ul> +</li> +<li>0.3.9 + +<ul class="task-list"> +<li> <a href="https://github.com/TimSchlechter/bootstrap-tagsinput/issues/48">#48: Type ahead stops when entering second character</a> +</li> +</ul> +</li> +<li>0.3.8 + +<ul class="task-list"> +<li> <a href="https://github.com/TimSchlechter/bootstrap-tagsinput/pull/43">#43: Add support for placeholder</a> +</li> +<li> <a href="https://github.com/TimSchlechter/bootstrap-tagsinput/pull/46">#46: ie 8 compatibility, replace indexOf method</a> +</li> +</ul> +</li> +<li>0.3.7 + +<ul class="task-list"> +<li> <a href="https://github.com/TimSchlechter/bootstrap-tagsinput/issues/39">#39: flash when duplicate is entered</a> +</li> +</ul> +</li> +<li>0.3.6 + +<ul class="task-list"> +<li> <a href="https://github.com/TimSchlechter/bootstrap-tagsinput/issues/34">#34: Error in ReloadPage</a> +</li> +</ul> +</li> +<li>0.3.5 + +<ul class="task-list"> +<li> <a href="https://github.com/TimSchlechter/bootstrap-tagsinput/issues/10">#10: confirmKeys option</a> +</li> +</ul> +</li> +<li>0.3.4 + +<ul class="task-list"> +<li> <a href="https://github.com/TimSchlechter/bootstrap-tagsinput/pull/24">#24: Add bsTagsInput angular directive & example for bootstrap3 with typeahea...</a> +</li> +<li> <a href="https://github.com/TimSchlechter/bootstrap-tagsinput/pull/28">#28: Limit number of tags, enable/disable input</a> +</li> +<li> <a href="https://github.com/TimSchlechter/bootstrap-tagsinput/pull/33">#33: Avoid conflict with other selects when checking for value presence</a> +</li> +</ul> +</li> +</ul> + +<h2> +<a id="user-content-license" class="anchor" href="#license" aria-hidden="true"><span class="octicon octicon-link"></span></a>License</h2> + +<p>This project is licensed under <a href="https://raw.github.com/TimSchlechter/bootstrap-tagsinput/master/LICENSE" title="Read more about the MIT license">MIT</a>.</p> +</article> + </div> + + </div> +</div> + +<a href="#jump-to-line" rel="facebox[.linejump]" data-hotkey="l" style="display:none">Jump to Line</a> +<div id="jump-to-line" style="display:none"> + <form accept-charset="UTF-8" class="js-jump-to-line-form"> + <input class="linejump-input js-jump-to-line-field" type="text" placeholder="Jump to line…" autofocus> + <button type="submit" class="button">Go</button> + </form> +</div> + + </div> + + </div><!-- /.repo-container --> + <div class="modal-backdrop"></div> + </div><!-- /.container --> + </div><!-- /.site --> + + + </div><!-- /.wrapper --> + + <div class="container"> + <div class="site-footer" role="contentinfo"> + <ul class="site-footer-links right"> + <li><a href="https://status.github.com/">Status</a></li> + <li><a href="https://developer.github.com">API</a></li> + <li><a href="http://training.github.com">Training</a></li> + <li><a href="http://shop.github.com">Shop</a></li> + <li><a href="/blog">Blog</a></li> + <li><a href="/about">About</a></li> + + </ul> + + <a href="/" aria-label="Homepage"> + <span class="mega-octicon octicon-mark-github" title="GitHub"></span> + </a> + + <ul class="site-footer-links"> + <li>© 2014 <span title="0.02664s from github-fe122-cp1-prd.iad.github.net">GitHub</span>, Inc.</li> + <li><a href="/site/terms">Terms</a></li> + <li><a href="/site/privacy">Privacy</a></li> + <li><a href="/security">Security</a></li> + <li><a href="/contact">Contact</a></li> + </ul> + </div><!-- /.site-footer --> +</div><!-- /.container --> + + + <div class="fullscreen-overlay js-fullscreen-overlay" id="fullscreen_overlay"> + <div class="fullscreen-container js-suggester-container"> + <div class="textarea-wrap"> + <textarea name="fullscreen-contents" id="fullscreen-contents" class="fullscreen-contents js-fullscreen-contents" placeholder=""></textarea> + <div class="suggester-container"> + <div class="suggester fullscreen-suggester js-suggester js-navigation-container"></div> + </div> + </div> + </div> + <div class="fullscreen-sidebar"> + <a href="#" class="exit-fullscreen js-exit-fullscreen tooltipped tooltipped-w" aria-label="Exit Zen Mode"> + <span class="mega-octicon octicon-screen-normal"></span> + </a> + <a href="#" class="theme-switcher js-theme-switcher tooltipped tooltipped-w" + aria-label="Switch themes"> + <span class="octicon octicon-color-mode"></span> + </a> + </div> +</div> + + + + <div id="ajax-error-message" class="flash flash-error"> + <span class="octicon octicon-alert"></span> + <a href="#" class="octicon octicon-x flash-close js-ajax-error-dismiss" aria-label="Dismiss error"></a> + Something went wrong with that request. Please try again. + </div> + + + <script crossorigin="anonymous" src="https://assets-cdn.github.com/assets/frameworks-fc447938e306b7b2c26a33cfee9dfda9052aeb1aa6ad84b72f1b35fd008efe9e.js" type="text/javascript"></script> + <script async="async" crossorigin="anonymous" src="https://assets-cdn.github.com/assets/github-56c56f7fe2ed90ca50b9eefebccd56f3b9729a85d7ba17f0f9c9ebd02f20a7e3.js" type="text/javascript"></script> + + + </body> +</html> + diff --git a/library/bootstrap-tagsinput/bootstrap-tagsinput.css b/library/bootstrap-tagsinput/bootstrap-tagsinput.css new file mode 100644 index 000000000..55f7c09df --- /dev/null +++ b/library/bootstrap-tagsinput/bootstrap-tagsinput.css @@ -0,0 +1,46 @@ +.bootstrap-tagsinput { + background-color: #fff; + border: 1px solid #ccc; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + display: inline-block; + padding: 4px 6px; + margin-bottom: 10px; + color: #555; + vertical-align: middle; + border-radius: 4px; + max-width: 100%; + line-height: 22px; + cursor: text; +} +.bootstrap-tagsinput input { + border: none; + box-shadow: none; + outline: none; + background-color: transparent; + padding: 0; + margin: 0; + width: auto !important; + max-width: inherit; +} +.bootstrap-tagsinput input:focus { + border: none; + box-shadow: none; +} +.bootstrap-tagsinput .tag { + margin-right: 2px; + color: white; +} +.bootstrap-tagsinput .tag [data-role="remove"] { + margin-left: 8px; + cursor: pointer; +} +.bootstrap-tagsinput .tag [data-role="remove"]:after { + content: "x"; + padding: 0px 2px; +} +.bootstrap-tagsinput .tag [data-role="remove"]:hover { + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); +} +.bootstrap-tagsinput .tag [data-role="remove"]:hover:active { + box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); +} diff --git a/library/bootstrap-tagsinput/bootstrap-tagsinput.js b/library/bootstrap-tagsinput/bootstrap-tagsinput.js new file mode 100644 index 000000000..89cc3b5a4 --- /dev/null +++ b/library/bootstrap-tagsinput/bootstrap-tagsinput.js @@ -0,0 +1,643 @@ +(function ($) { + "use strict"; + + var defaultOptions = { + tagClass: function(item) { + return 'label label-info'; + }, + itemValue: function(item) { + return item ? item.toString() : item; + }, + itemText: function(item) { + return this.itemValue(item); + }, + freeInput: true, + addOnBlur: true, + maxTags: undefined, + maxChars: undefined, + confirmKeys: [13, 44], + onTagExists: function(item, $tag) { + $tag.hide().fadeIn(); + }, + trimValue: false, + allowDuplicates: false + }; + + /** + * Constructor function + */ + function TagsInput(element, options) { + this.itemsArray = []; + + this.$element = $(element); + this.$element.hide(); + + this.isSelect = (element.tagName === 'SELECT'); + this.multiple = (this.isSelect && element.hasAttribute('multiple')); + this.objectItems = options && options.itemValue; + this.placeholderText = element.hasAttribute('placeholder') ? this.$element.attr('placeholder') : ''; + this.inputSize = Math.max(1, this.placeholderText.length); + + this.$container = $('<div class="bootstrap-tagsinput"></div>'); + this.$input = $('<input type="text" placeholder="' + this.placeholderText + '"/>').appendTo(this.$container); + + this.$element.after(this.$container); + + var inputWidth = (this.inputSize < 3 ? 3 : this.inputSize) + "em"; + this.$input.get(0).style.cssText = "width: " + inputWidth + " !important;"; + this.build(options); + } + + TagsInput.prototype = { + constructor: TagsInput, + + /** + * Adds the given item as a new tag. Pass true to dontPushVal to prevent + * updating the elements val() + */ + add: function(item, dontPushVal) { + var self = this; + + if (self.options.maxTags && self.itemsArray.length >= self.options.maxTags) + return; + + // Ignore falsey values, except false + if (item !== false && !item) + return; + + // Trim value + if (typeof item === "string" && self.options.trimValue) { + item = $.trim(item); + } + + // Throw an error when trying to add an object while the itemValue option was not set + if (typeof item === "object" && !self.objectItems) + throw("Can't add objects when itemValue option is not set"); + + // Ignore strings only containg whitespace + if (item.toString().match(/^\s*$/)) + return; + + // If SELECT but not multiple, remove current tag + if (self.isSelect && !self.multiple && self.itemsArray.length > 0) + self.remove(self.itemsArray[0]); + + if (typeof item === "string" && this.$element[0].tagName === 'INPUT') { + var items = item.split(','); + if (items.length > 1) { + for (var i = 0; i < items.length; i++) { + this.add(items[i], true); + } + + if (!dontPushVal) + self.pushVal(); + return; + } + } + + // raise beforeItemAdd arg + var beforeItemAddEvent = $.Event('beforeItemAdd', { item: item, cancel: false }); + self.$element.trigger(beforeItemAddEvent); + if (beforeItemAddEvent.cancel) + return; + + item = beforeItemAddEvent.item + + var itemValue = self.options.itemValue(item), + itemText = self.options.itemText(item), + tagClass = self.options.tagClass(item); + + // Ignore items allready added + var existing = $.grep(self.itemsArray, function(item) { return self.options.itemValue(item) === itemValue; } )[0]; + if (existing && !self.options.allowDuplicates) { + // Invoke onTagExists + if (self.options.onTagExists) { + var $existingTag = $(".tag", self.$container).filter(function() { return $(this).data("item") === existing; }); + self.options.onTagExists(item, $existingTag); + } + return; + } + + // if length greater than limit + if (self.items().toString().length + item.length + 1 > self.options.maxInputLength) + return; + + // register item in internal array and map + self.itemsArray.push(item); + + //remove placeholder if there is an item, restore if no item(s) + if (self.itemsArray.length) + self.$input.attr('placeholder', ''); + else + self.$input.attr('placeholder', self.placeholderText); + + // add a tag element + var $tag = $('<span class="tag ' + htmlEncode(tagClass) + '">' + htmlEncode(itemText) + '<span data-role="remove"></span></span>'); + $tag.data('item', item); + self.findInputWrapper().before($tag); + $tag.after(' '); + + // add <option /> if item represents a value not present in one of the <select />'s options + if (self.isSelect && !$('option[value="' + encodeURIComponent(itemValue) + '"]',self.$element)[0]) { + var $option = $('<option selected>' + htmlEncode(itemText) + '</option>'); + $option.data('item', item); + $option.attr('value', itemValue); + self.$element.append($option); + } + + //remove placeholder if there is an item, restore if no item(s) + if (self.itemsArray.length) + self.$input.attr('placeholder', ''); + else + self.$input.attr('placeholder', self.placeholderText); + + if (!dontPushVal) + self.pushVal(); + + // Add class when reached maxTags + if (self.options.maxTags === self.itemsArray.length || self.items().toString().length === self.options.maxInputLength) + self.$container.addClass('bootstrap-tagsinput-max'); + + self.$element.trigger($.Event('itemAdded', { item: item })); + }, + + /** + * Removes the given item. Pass true to dontPushVal to prevent updating the + * elements val() + */ + remove: function(item, dontPushVal) { + var self = this; + + if (self.objectItems) { + if (typeof item === "object") + item = $.grep(self.itemsArray, function(other) { return self.options.itemValue(other) == self.options.itemValue(item); } ); + else + item = $.grep(self.itemsArray, function(other) { return self.options.itemValue(other) == item; } ); + + item = item[item.length-1]; + } + + if (item) { + var beforeItemRemoveEvent = $.Event('beforeItemRemove', { item: item, cancel: false }); + self.$element.trigger(beforeItemRemoveEvent); + if (beforeItemRemoveEvent.cancel) + return; + + $('.tag', self.$container).filter(function() { return $(this).data('item') === item; }).remove(); + $('option', self.$element).filter(function() { return $(this).data('item') === item; }).remove(); + if($.inArray(item, self.itemsArray) !== -1) + self.itemsArray.splice($.inArray(item, self.itemsArray), 1); + } + + //remove placeholder if there is an item, restore if no item(s) + if (self.itemsArray.length) + self.$input.attr('placeholder', ''); + else + self.$input.attr('placeholder', self.placeholderText); + + if (!dontPushVal) + self.pushVal(); + + // Remove class when reached maxTags + if (self.options.maxTags > self.itemsArray.length) + self.$container.removeClass('bootstrap-tagsinput-max'); + + self.$element.trigger($.Event('itemRemoved', { item: item })); + }, + + /** + * Removes all items + */ + removeAll: function() { + var self = this; + + $('.tag', self.$container).remove(); + $('option', self.$element).remove(); + + while(self.itemsArray.length > 0) + self.itemsArray.pop(); + + //remove placeholder if there is an item, restore if no item(s) + if (self.itemsArray.length) + self.$input.attr('placeholder', ''); + else + self.$input.attr('placeholder', self.placeholderText); + + self.pushVal(); + }, + + /** + * Refreshes the tags so they match the text/value of their corresponding + * item. + */ + refresh: function() { + var self = this; + $('.tag', self.$container).each(function() { + var $tag = $(this), + item = $tag.data('item'), + itemValue = self.options.itemValue(item), + itemText = self.options.itemText(item), + tagClass = self.options.tagClass(item); + + // Update tag's class and inner text + $tag.attr('class', null); + $tag.addClass('tag ' + htmlEncode(tagClass)); + $tag.contents().filter(function() { + return this.nodeType == 3; + })[0].nodeValue = htmlEncode(itemText); + + if (self.isSelect) { + var option = $('option', self.$element).filter(function() { return $(this).data('item') === item; }); + option.attr('value', itemValue); + } + }); + }, + + /** + * Returns the items added as tags + */ + items: function() { + return this.itemsArray; + }, + + /** + * Assembly value by retrieving the value of each item, and set it on the + * element. + */ + pushVal: function() { + var self = this, + val = $.map(self.items(), function(item) { + return self.options.itemValue(item).toString(); + }); + + self.$element.val(val, true).trigger('change'); + }, + + /** + * Initializes the tags input behaviour on the element + */ + build: function(options) { + var self = this; + + self.options = $.extend({}, defaultOptions, options); + // When itemValue is set, freeInput should always be false + if (self.objectItems) + self.options.freeInput = false; + + makeOptionItemFunction(self.options, 'itemValue'); + makeOptionItemFunction(self.options, 'itemText'); + makeOptionFunction(self.options, 'tagClass'); + + // Typeahead Bootstrap version 2.3.2 + if (self.options.typeahead) { + var typeahead = self.options.typeahead || {}; + + makeOptionFunction(typeahead, 'source'); + + self.$input.typeahead($.extend({}, typeahead, { + source: function (query, process) { + function processItems(items) { + var texts = []; + + for (var i = 0; i < items.length; i++) { + var text = self.options.itemText(items[i]); + map[text] = items[i]; + texts.push(text); + } + process(texts); + } + + this.map = {}; + var map = this.map, + data = typeahead.source(query); + + if ($.isFunction(data.success)) { + // support for Angular callbacks + data.success(processItems); + } else if ($.isFunction(data.then)) { + // support for Angular promises + data.then(processItems); + } else { + // support for functions and jquery promises + $.when(data) + .then(processItems); + } + }, + updater: function (text) { + self.add(this.map[text]); + }, + matcher: function (text) { + return (text.toLowerCase().indexOf(this.query.trim().toLowerCase()) !== -1); + }, + sorter: function (texts) { + return texts.sort(); + }, + highlighter: function (text) { + var regex = new RegExp( '(' + this.query + ')', 'gi' ); + return text.replace( regex, "<strong>$1</strong>" ); + } + })); + } + + // typeahead.js + if (self.options.typeaheadjs) { + var typeaheadjs = self.options.typeaheadjs || {}; + + self.$input.typeahead(null, typeaheadjs).on('typeahead:selected', $.proxy(function (obj, datum) { + if (typeaheadjs.valueKey) + self.add(datum[typeaheadjs.valueKey]); + else + self.add(datum); + self.$input.typeahead('val', ''); + }, self)); + } + + self.$container.on('click', $.proxy(function(event) { + if (! self.$element.attr('disabled')) { + self.$input.removeAttr('disabled'); + } + self.$input.focus(); + }, self)); + + if (self.options.addOnBlur && self.options.freeInput) { + self.$input.on('focusout', $.proxy(function(event) { + // HACK: only process on focusout when no typeahead opened, to + // avoid adding the typeahead text as tag + if ($('.typeahead, .twitter-typeahead', self.$container).length === 0) { + self.add(self.$input.val()); + self.$input.val(''); + } + }, self)); + } + + + self.$container.on('keydown', 'input', $.proxy(function(event) { + var $input = $(event.target), + $inputWrapper = self.findInputWrapper(); + + if (self.$element.attr('disabled')) { + self.$input.attr('disabled', 'disabled'); + return; + } + + switch (event.which) { + // BACKSPACE + case 8: + if (doGetCaretPosition($input[0]) === 0) { + var prev = $inputWrapper.prev(); + if (prev) { + self.remove(prev.data('item')); + } + } + break; + + // DELETE + case 46: + if (doGetCaretPosition($input[0]) === 0) { + var next = $inputWrapper.next(); + if (next) { + self.remove(next.data('item')); + } + } + break; + + // LEFT ARROW + case 37: + // Try to move the input before the previous tag + var $prevTag = $inputWrapper.prev(); + if ($input.val().length === 0 && $prevTag[0]) { + $prevTag.before($inputWrapper); + $input.focus(); + } + break; + // RIGHT ARROW + case 39: + // Try to move the input after the next tag + var $nextTag = $inputWrapper.next(); + if ($input.val().length === 0 && $nextTag[0]) { + $nextTag.after($inputWrapper); + $input.focus(); + } + break; + default: + // ignore + } + + // Reset internal input's size + var textLength = $input.val().length, + wordSpace = Math.ceil(textLength / 5), + size = textLength + wordSpace + 1; + $input.attr('size', Math.max(this.inputSize, $input.val().length)); + }, self)); + + self.$container.on('keypress', 'input', $.proxy(function(event) { + var $input = $(event.target); + + if (self.$element.attr('disabled')) { + self.$input.attr('disabled', 'disabled'); + return; + } + + var text = $input.val(), + maxLengthReached = self.options.maxChars && text.length >= self.options.maxChars; + if (self.options.freeInput && (keyCombinationInList(event, self.options.confirmKeys) || maxLengthReached)) { + self.add(maxLengthReached ? text.substr(0, self.options.maxChars) : text); + $input.val(''); + event.preventDefault(); + } + + // Reset internal input's size + var textLength = $input.val().length, + wordSpace = Math.ceil(textLength / 5), + size = textLength + wordSpace + 1; + $input.attr('size', Math.max(this.inputSize, $input.val().length)); + }, self)); + + // Remove icon clicked + self.$container.on('click', '[data-role=remove]', $.proxy(function(event) { + if (self.$element.attr('disabled')) { + return; + } + self.remove($(event.target).closest('.tag').data('item')); + }, self)); + + // Only add existing value as tags when using strings as tags + if (self.options.itemValue === defaultOptions.itemValue) { + if (self.$element[0].tagName === 'INPUT') { + self.add(self.$element.val()); + } else { + $('option', self.$element).each(function() { + self.add($(this).attr('value'), true); + }); + } + } + }, + + /** + * Removes all tagsinput behaviour and unregsiter all event handlers + */ + destroy: function() { + var self = this; + + // Unbind events + self.$container.off('keypress', 'input'); + self.$container.off('click', '[role=remove]'); + + self.$container.remove(); + self.$element.removeData('tagsinput'); + self.$element.show(); + }, + + /** + * Sets focus on the tagsinput + */ + focus: function() { + this.$input.focus(); + }, + + /** + * Returns the internal input element + */ + input: function() { + return this.$input; + }, + + /** + * Returns the element which is wrapped around the internal input. This + * is normally the $container, but typeahead.js moves the $input element. + */ + findInputWrapper: function() { + var elt = this.$input[0], + container = this.$container[0]; + while(elt && elt.parentNode !== container) + elt = elt.parentNode; + + return $(elt); + } + }; + + /** + * Register JQuery plugin + */ + $.fn.tagsinput = function(arg1, arg2) { + var results = []; + + this.each(function() { + var tagsinput = $(this).data('tagsinput'); + // Initialize a new tags input + if (!tagsinput) { + tagsinput = new TagsInput(this, arg1); + $(this).data('tagsinput', tagsinput); + results.push(tagsinput); + + if (this.tagName === 'SELECT') { + $('option', $(this)).attr('selected', 'selected'); + } + + // Init tags from $(this).val() + $(this).val($(this).val()); + } else if (!arg1 && !arg2) { + // tagsinput already exists + // no function, trying to init + results.push(tagsinput); + } else if(tagsinput[arg1] !== undefined) { + // Invoke function on existing tags input + var retVal = tagsinput[arg1](arg2); + if (retVal !== undefined) + results.push(retVal); + } + }); + + if ( typeof arg1 == 'string') { + // Return the results from the invoked function calls + return results.length > 1 ? results : results[0]; + } else { + return results; + } + }; + + $.fn.tagsinput.Constructor = TagsInput; + + /** + * Most options support both a string or number as well as a function as + * option value. This function makes sure that the option with the given + * key in the given options is wrapped in a function + */ + function makeOptionItemFunction(options, key) { + if (typeof options[key] !== 'function') { + var propertyName = options[key]; + options[key] = function(item) { return item[propertyName]; }; + } + } + function makeOptionFunction(options, key) { + if (typeof options[key] !== 'function') { + var value = options[key]; + options[key] = function() { return value; }; + } + } + /** + * HtmlEncodes the given value + */ + var htmlEncodeContainer = $('<div />'); + function htmlEncode(value) { + if (value) { + return htmlEncodeContainer.text(value).html(); + } else { + return ''; + } + } + + /** + * Returns the position of the caret in the given input field + * http://flightschool.acylt.com/devnotes/caret-position-woes/ + */ + function doGetCaretPosition(oField) { + var iCaretPos = 0; + if (document.selection) { + oField.focus (); + var oSel = document.selection.createRange(); + oSel.moveStart ('character', -oField.value.length); + iCaretPos = oSel.text.length; + } else if (oField.selectionStart || oField.selectionStart == '0') { + iCaretPos = oField.selectionStart; + } + return (iCaretPos); + } + + /** + * Returns boolean indicates whether user has pressed an expected key combination. + * @param object keyPressEvent: JavaScript event object, refer + * http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html + * @param object lookupList: expected key combinations, as in: + * [13, {which: 188, shiftKey: true}] + */ + function keyCombinationInList(keyPressEvent, lookupList) { + var found = false; + $.each(lookupList, function (index, keyCombination) { + if (typeof (keyCombination) === 'number' && keyPressEvent.which === keyCombination) { + found = true; + return false; + } + + if (keyPressEvent.which === keyCombination.which) { + var alt = !keyCombination.hasOwnProperty('altKey') || keyPressEvent.altKey === keyCombination.altKey, + shift = !keyCombination.hasOwnProperty('shiftKey') || keyPressEvent.shiftKey === keyCombination.shiftKey, + ctrl = !keyCombination.hasOwnProperty('ctrlKey') || keyPressEvent.ctrlKey === keyCombination.ctrlKey; + if (alt && shift && ctrl) { + found = true; + return false; + } + } + }); + + return found; + } + + /** + * Initialize tagsinput behaviour on inputs and selects which have + * data-role=tagsinput + */ + $(function() { + $("input[data-role=tagsinput], select[multiple][data-role=tagsinput]").tagsinput(); + }); +})(window.jQuery); |