(function (angular) { var undefined; angular.module("ui.materialize", ["ui.materialize.ngModel", "ui.materialize.collapsible", "ui.materialize.toast", "ui.materialize.sidenav", "ui.materialize.material_select", "ui.materialize.dropdown", "ui.materialize.inputfield", "ui.materialize.input_date", "ui.materialize.tabs", "ui.materialize.pagination", "ui.materialize.pushpin", "ui.materialize.scrollspy", "ui.materialize.parallax","ui.materialize.modal", "ui.materialize.tooltipped", "ui.materialize.slider", "ui.materialize.materialboxed", "ui.materialize.scrollFire", "ui.materialize.nouislider", "ui.materialize.input_clock", "ui.materialize.carousel", "ui.materialize.chips"]); /* example usage: <div scroll-fire="func('Scrolled', 2000)" ></div> */ angular.module("ui.materialize.scrollFire", []) .directive("scrollFire", ["$compile", "$timeout", function ($compile, $timeout) { return { restrict: "A", scope: { offset: "@", scrollFire: "&" }, link: function (scope, element, attrs) { var offset = scope.offset; if (!angular.isDefined(scope.offset)) { offset = 0; } offset = Number(offset) || 0; var fired = false; var handler = throttle(function () { if (fired) { return; } var windowScroll = window.pageYOffset + window.innerHeight; var elementOffset = element[0].getBoundingClientRect().top + window.pageYOffset; if (windowScroll > (elementOffset + offset)) { fired = true; scope.scrollFire({}); stop(); } }, 100); function stop() { $(window).off("scroll resize blur focus", handler); } $(window).on("scroll resize blur focus", handler); handler(); scope.$on('$destroy', stop); } }; }]); // The throttle function from underscore: https://github.com/jashkenas/underscore/blob/master/underscore.js function throttle(func, wait) { var timeout, context, args, result; var previous = 0; var later = function() { previous = + new Date(); timeout = null; result = func.apply(context, args); if (!timeout) context = args = null; }; var throttled = function() { var now = + new Date(); var remaining = wait - (now - previous); context = this; args = arguments; if (remaining <= 0 || remaining > wait) { if (timeout) { clearTimeout(timeout); timeout = null; } previous = now; result = func.apply(context, args); if (!timeout) context = args = null; } else if (!timeout) { timeout = setTimeout(later, remaining); } return result; }; throttled.cancel = function() { clearTimeout(timeout); previous = 0; timeout = context = args = null; }; return throttled; }; angular.module("ui.materialize.ngModel", []) .directive("ngModel",["$timeout", function($timeout){ return { restrict: 'A', priority: -1, // lower priority than built-in ng-model so it runs first link: function(scope, element, attr) { scope.$watch(attr.ngModel,function(value, oldValue){ $timeout(function () { // To stop an infinite feedback-loop with material multiple-select. if (value instanceof Array && oldValue instanceof Array) { if (value.length == oldValue.length) { return; } } if (element.is('select')) { return; } // This fix is mainly to get placeholders to appear correctly, and it apparently screws things for the selects, so only doing this on something that isn't a select. if (value){ element.trigger("change"); } else if(element.attr('placeholder') === undefined) { if(!element.is(":focus")) element.trigger("blur"); } }); }); } }; }]); /* example usage: <div input-field> <div chips ng-model="vm.lists" secondary-placeholder="first seen placeholder" placeholder="placeholder on th side of the chips"></div> </div> */ angular.module('ui.materialize.chips', []) .directive('chips',['$timeout', function ($timeout) { return { restrict: 'A', scope: { ngModel: '=', placeholder: '@', secondaryPlaceholder: '@', }, link: function (scope, element, attrs) { $timeout(function () { element.material_chip({ data: scope.ngModel || [], placeholder: scope.placeholder || '', secondaryPlaceholder: scope.secondaryPlaceholder || '', }) element.on('chip.add', function (e, chip) { scope.ngModel =element.data().chips.map(function (item) { return item.tag }) scope.$apply() }) element.on('chip.delete', function (e, chip) { scope.ngModel =element.data().chips.map(function (item) { return item.tag }) scope.$apply() }) }) } }; }]); /* example usage: <div slider height='500' transition='400'></div> */ angular.module("ui.materialize.slider", []) .directive("slider", ["$timeout", function($timeout){ return { restrict: 'A', scope: { height: '=', transition: '=', interval: '=', indicators: '=' }, link: function(scope, element, attrs) { element.addClass("slider"); $timeout(function(){ element.slider({ height: (angular.isDefined(scope.height)) ? scope.height : 400, transition: (angular.isDefined(scope.transition)) ? scope.transition : 500, interval: (angular.isDefined(scope.interval)) ? scope.interval : 6000, indicators: (angular.isDefined(scope.indicators)) ? scope.indicators : true }); }); } }; }]); /* example usage: <div carousel height='500' transition='400'></div> */ angular.module("ui.materialize.carousel", []) .directive("carousel", ["$timeout", function($timeout){ return { restrict: 'A', scope: { duration: '@', dist: '@', shift: '@', padding: '@', fullWidth: '@', indicators: '@', noWrap: '@' }, link: function(scope, element, attrs) { element.addClass("carousel"); $timeout(function(){ element.carousel({ duration: (angular.isDefined(scope.duration)) ? scope.duration : 200, dist: (angular.isDefined(scope.dist)) ? scope.dist : -100, shift: (angular.isDefined(scope.shift)) ? scope.shift : 0, padding: (angular.isDefined(scope.padding)) ? scope.padding : 0, fullWidth: (angular.isDefined(scope.fullWidth)) ? scope.fullWidth : false, indicators: (angular.isDefined(scope.indicators)) ? scope.indicators : false, noWrap: (angular.isDefined(scope.noWrap)) ? scope.noWrap : false }); }); } }; }]); angular.module("ui.materialize.collapsible", []) .directive("collapsible", ["$timeout", function ($timeout) { return { link: function (scope, element, attrs) { $timeout(function () { element.collapsible(); }); if ("watch" in attrs) { scope.$watch(function () { return element[0].innerHTML; }, function (oldVal, newVal) { if (oldVal !== newVal) { $timeout(function () { element.collapsible(); }); } }); } } }; }]); angular.module("ui.materialize.parallax", []) .directive("parallax", ["$timeout", function($timeout){ return { link: function(scope, element, attrs) { $timeout(function(){ element.parallax(); }); } }; }]); angular.module("ui.materialize.toast", []) .constant("toastConfig", { duration: 3000 }) .directive("toast", ["toastConfig", function (toastConfig) { return { scope: { message: "@", duration: "@", callback: "&" }, link: function (scope, element, attrs) { element.bind(attrs.toast, function () { var message = (angular.isDefined(scope.message)) ? scope.message : ""; var toastclass = (angular.isDefined(attrs.toastclass)) ? attrs.toastclass : ""; Materialize.toast(message, scope.duration ? scope.duration : toastConfig.duration, toastclass, scope.callback); }); } }; }]); angular.module('ui.materialize.pushpin', []) .directive('pushpin', [function(){ return { restrict: 'AE', require: [ '?pushpinTop', '?pushpinOffset', '?pushpinBottom' ], link: function (scope, element, attrs) { var top = attrs.pushpinTop || 0; var offset = attrs.pushpinOffset || 0; var bottom = attrs.pushpinBottom || Infinity; setTimeout(function () { element.pushpin({top: top, offset: offset, bottom: bottom}); }, 0); } }; }]); // TODO: Add some documentation for this. angular.module("ui.materialize.scrollspy", []) .directive("scrollspy", ["$timeout", function($timeout){ return { restrict: 'A', link: function(scope, element, attrs) { element.addClass("scrollspy"); $timeout(function(){ element.scrollSpy(); }); } }; }]); angular.module("ui.materialize.tabs", []) .directive("tabs", ["$timeout", function($timeout){ return { scope: { reload: '=' }, link: function (scope, element, attrs) { element.addClass("tabs"); $timeout(function() { element.tabs(); }); scope.$watch('reload', function(newValue) { if (newValue === true) { element.tabs(); scope.reload = false; } }); } }; }]); // Example: <a href="#" data-activates="nav-mobile" class="button-collapse top-nav" data-sidenav="left" data-menuwidth="500" data-closeonclick="true"> // data-activates is handled by the jQuery plugin. angular.module("ui.materialize.sidenav", []) .directive("sidenav", [function () { return { scope: { menuwidth: "@", closeonclick: "@" }, link: function (scope, element, attrs) { element.sideNav({ menuWidth: (angular.isDefined(scope.menuwidth)) ? parseInt(scope.menuwidth, 10) : undefined, edge: attrs.sidenav ? attrs.sidenav : "left", closeOnClick: (angular.isDefined(scope.closeonclick)) ? scope.closeonclick == "true" : undefined }); } }; }]); // This works, unless the content inside the select changes. angular.module("ui.materialize.material_select", []) .directive("materialSelect", ["$compile", "$timeout", function ($compile, $timeout) { return { link: function (scope, element, attrs) { if (element.is("select")) { //BugFix 139: In case of multiple enabled. Avoid the circular looping. function initSelect(newVal, oldVal) { if (attrs.multiple) { if (oldVal !== undefined && newVal !== undefined) { if (oldVal.length === newVal.length) { return; } } var activeUl = element.siblings("ul.active"); if (newVal !== undefined && activeUl.length) { // If select is open var selectedOptions = activeUl.children("li.active").length; // Number of selected elements if (selectedOptions == newVal.length) { return; } } } element.siblings(".caret").remove(); function fixActive () { if (!attrs.multiple) { var value = element.val(); var ul = element.siblings("ul"); ul.find("li").each(function () { var that = $(this); if (that.text() === value) { that.addClass("active"); } }); } } scope.$evalAsync(function () { //element.material_select(); //Lines 301-311 fix Dogfalo/materialize/issues/901 and should be removed and the above uncommented whenever 901 is fixed element.material_select(function () { if (!attrs.multiple) { element.siblings('input.select-dropdown').trigger('close'); } fixActive(); }); var onMouseDown = function (e) { // preventing the default still allows the scroll, but blocks the blur. // We're inside the scrollbar if the clientX is >= the clientWidth. if (e.clientX >= e.target.clientWidth || e.clientY >= e.target.clientHeight) { e.preventDefault(); } }; element.siblings('input.select-dropdown').off("mousedown.material_select_fix").on('mousedown.material_select_fix', onMouseDown); fixActive(); element.siblings('input.select-dropdown').off("click.material_select_fix").on("click.material_select_fix", function () { $("input.select-dropdown").not(element.siblings("input.select-dropdown")).trigger("close"); }); }); } $timeout(initSelect); if (attrs.ngModel) { if (attrs.ngModel && !angular.isDefined(scope.$eval(attrs.ngModel))) { // This whole thing fixes that if initialized with undefined, then a ghost value option is inserted. If this thing wasn't done, then adding the 'watch' attribute could also fix it. #160 var hasChangedFromUndefined = false; scope.$watch(attrs.ngModel, function (newVal, oldVal) { if (!hasChangedFromUndefined && angular.isDefined(scope.$eval(attrs.ngModel))) { hasChangedFromUndefined = true; initSelect(); // initSelect without arguments forces it to actually run. } else { initSelect(newVal, oldVal); } }); } else { scope.$watch(attrs.ngModel, initSelect); } } if ("watch" in attrs) { scope.$watch(function () { return element[0].innerHTML; }, function (newValue, oldValue) { if (newValue !== oldValue) { $timeout(initSelect); } }); } if(attrs.ngDisabled) { scope.$watch(attrs.ngDisabled, initSelect) } } } }; }]); /* Example usage, notice the empty dropdown tag in the dropdown trigger. <!-- Dropdown Trigger --> <a class='dropdown-button btn' href='javascript:void(0);' data-activates='demoDropdown' dropdown constrain-width="false"> Select a demo </a> <!-- Dropdown Structure --> <ul id='demoDropdown' class='dropdown-content'> <li ng-repeat="demo in demoDefiniftions"> <a href="javascript:void(0);" ng-click="selectDemo(demo)">{{demo.name}}</a> </li> </ul>*/ angular.module("ui.materialize.dropdown", []) .directive("dropdown", ["$timeout", function ($timeout) { return { scope: { inDuration: "@", outDuration: "@", constrainWidth: "@", hover: "@", alignment: "@", gutter: "@", belowOrigin: "@" }, link: function (scope, element, attrs) { $timeout(function () { element.dropdown({ inDuration: (angular.isDefined(scope.inDuration)) ? scope.inDuration : undefined, outDuration: (angular.isDefined(scope.outDuration)) ? scope.outDuration : undefined, constrainWidth: (angular.isDefined(scope.constrainWidth)) ? scope.constrainWidth : undefined, hover: (angular.isDefined(scope.hover)) ? scope.hover : undefined, alignment: (angular.isDefined(scope.alignment)) ? scope.alignment : undefined, gutter: (angular.isDefined(scope.gutter)) ? scope.gutter : undefined, belowOrigin: (angular.isDefined(scope.belowOrigin)) ? scope.belowOrigin : undefined }); }); } }; }]); /** * Instead of adding the .input-field class to a div surrounding a label and input, add the attribute input-field. * That way it will also work when angular destroys/recreates the elements. * * Example: <inputfield style="margin-top:10px"> <label>{{name}}:</label> <input type="text" name="{{name}}" ng-model="value"> </inputfield> */ angular.module("ui.materialize.inputfield", []) .directive('inputField', ["$timeout", function ($timeout) { var inputLabelIdCounter = 0; return { transclude: true, scope: {}, link: function (scope, element) { $timeout(function () { var input = element.find("> > input, > > textarea"); var label = element.find("> > label"); if (input.length == 1 && label.length == 1 && !input.attr("id") && !label.attr("for")) { var id = "angularMaterializeID" + inputLabelIdCounter++; input.attr("id", id); label.attr("for", id); } Materialize.updateTextFields(); // The "> > [selector]", is to restrict to only those tags that are direct children of the directive element. Otherwise we might hit to many elements with the selectors. // Triggering autoresize of the textareas. element.find("> > .materialize-textarea").each(function () { var that = $(this); that.addClass("materialize-textarea"); that.data("original-height", that.height()); that.data("previous-length", that.val().length); that.trigger("autoresize"); var model = that.attr("ng-model"); if (model) { scope.$parent.$watch(model, function (a, b) { if (a !== b) { $timeout(function () { that.trigger("autoresize"); }); } }); } }); // Adding char-counters. element.find('> > .materialize-textarea, > > input').each(function (index, countable) { countable = angular.element(countable); if (!countable.siblings('span[class="character-counter"]').length) { countable.characterCounter(); } }); }); }, template: '<div ng-transclude class="input-field"></div>' }; }]); /** * Add pickadate directive * Type text is mandatory * Example: <input input-date type="text" name="created" id="inputCreated" ng-model="currentTime" format="dd/mm/yyyy" months-full="{{ monthFr }}" months-short="{{ monthShortFr }}" weekdays-full="{{ weekdaysFullFr }}" weekdays-short="{{ weekdaysShortFr }}" weekdays-letter="{{ weekdaysLetterFr }}" disable="disable" today="today" clear="clear" close="close" on-start="onStart()" on-render="onRender()" on-open="onOpen()" on-close="onClose()" on-set="onSet()" on-stop="onStop()" /> */ angular.module("ui.materialize.input_date", []) .directive('inputDate', ["$compile", "$timeout", function ($compile, $timeout) { // Fix for issue 46. This gotta be a bug in the materialize code, but this fixes it. var style = $('<style>#inputCreated_root {outline: none;}</style>'); $('html > head').append(style); // Define Prototype Date format // Use like this // today = new Date(); // var dateString = today.format("dd-m-yy"); var dateFormat = function () { var token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g, timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g, timezoneClip = /[^-+\dA-Z]/g, pad = function (val, len) { val = String(val); len = len || 2; while (val.length < len) { val = "0" + val; } return val; }; // Regexes and supporting functions are cached through closure return function (date, mask, utc) { var dF = dateFormat; // You can't provide utc if you skip other args (use the "UTC:" mask prefix) if (arguments.length === 1 && Object.prototype.toString.call(date) == "[object String]" && !/\d/.test(date)) { mask = date; date = undefined; } // Passing date through Date applies Date.parse, if necessary date = date ? new Date(date) : new Date(); if (isNaN(date)) throw SyntaxError("invalid date"); mask = String(dF.masks[mask] || mask || dF.masks["default"]); // Allow setting the utc argument via the mask if (mask.slice(0, 4) == "UTC:") { mask = mask.slice(4); utc = true; } var _ = utc ? "getUTC" : "get", d = date[ _ + "Date" ](), D = date[ _ + "Day" ](), m = date[ _ + "Month" ](), y = date[ _ + "FullYear" ](), H = date[ _ + "Hours" ](), M = date[ _ + "Minutes" ](), s = date[ _ + "Seconds" ](), L = date[ _ + "Milliseconds" ](), o = utc ? 0 : date.getTimezoneOffset(), flags = { d: d, dd: pad(d), ddd: dF.i18n.dayNames[D], dddd: dF.i18n.dayNames[D + 7], m: m + 1, mm: pad(m + 1), mmm: dF.i18n.monthNames[m], mmmm: dF.i18n.monthNames[m + 12], yy: String(y).slice(2), yyyy: y, h: H % 12 || 12, hh: pad(H % 12 || 12), H: H, HH: pad(H), M: M, MM: pad(M), s: s, ss: pad(s), l: pad(L, 3), L: pad(L > 99 ? Math.round(L / 10) : L), t: H < 12 ? "a" : "p", tt: H < 12 ? "am" : "pm", T: H < 12 ? "A" : "P", TT: H < 12 ? "AM" : "PM", Z: utc ? "UTC" : (String(date).match(timezone) || [""]).pop().replace(timezoneClip, ""), o: (o > 0 ? "-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4), S: ["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10] }; return mask.replace(token, function ($0) { return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1); }); }; }(); // Some common format strings dateFormat.masks = { "default": "ddd mmm dd yyyy HH:MM:ss", shortDate: "m/d/yy", mediumDate: "mmm d, yyyy", longDate: "mmmm d, yyyy", fullDate: "dddd, mmmm d, yyyy", shortTime: "h:MM TT", mediumTime: "h:MM:ss TT", longTime: "h:MM:ss TT Z", isoDate: "yyyy-mm-dd", isoTime: "HH:MM:ss", isoDateTime: "yyyy-mm-dd'T'HH:MM:ss", isoUtcDateTime: "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'" }; // Internationalization strings dateFormat.i18n = { dayNames: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], monthNames: [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ] }; // For convenience... Date.prototype.format = function (mask, utc) { return dateFormat(this, mask, utc); }; /** * Validate date object * @param {Date} date * @return {Boolean} */ var isValidDate = function(date) { if( Object.prototype.toString.call(date) === '[object Date]' ) { return !isNaN(date.getTime()); } return false; }; return { require: 'ngModel', scope: { container: "@", format: "@", formatSubmit: "@", monthsFull: "@", monthsShort: "@", weekdaysFull: "@", weekdaysShort: "@", weekdaysLetter: "@", firstDay: "=", disable: "=", today: "=", clear: "=", close: "=", selectYears: "=", selectMonths: "=", onStart: "&", onRender: "&", onOpen: "&", onClose: "&", onSet: "&", onStop: "&", ngReadonly: "=?", max: "@", min: "@" }, link: function (scope, element, attrs, ngModelCtrl) { ngModelCtrl.$formatters.unshift(function (modelValue) { if (modelValue) { var date = new Date(modelValue); return (angular.isDefined(scope.format)) ? date.format(scope.format) : date.format('d mmmm, yyyy'); } return null; }); var monthsFull = (angular.isDefined(scope.monthsFull)) ? scope.$eval(scope.monthsFull) : undefined, monthsShort = (angular.isDefined(scope.monthsShort)) ? scope.$eval(scope.monthsShort) : undefined, weekdaysFull = (angular.isDefined(scope.weekdaysFull)) ? scope.$eval(scope.weekdaysFull) : undefined, weekdaysShort = (angular.isDefined(scope.weekdaysShort)) ? scope.$eval(scope.weekdaysShort) : undefined, weekdaysLetter = (angular.isDefined(scope.weekdaysLetter)) ? scope.$eval(scope.weekdaysLetter) : undefined; $compile(element.contents())(scope); if (!(scope.ngReadonly)) { $timeout(function () { var options = { container : scope.container, format: (angular.isDefined(scope.format)) ? scope.format : undefined, formatSubmit: (angular.isDefined(scope.formatSubmit)) ? scope.formatSubmit : undefined, monthsFull: (angular.isDefined(monthsFull)) ? monthsFull : undefined, monthsShort: (angular.isDefined(monthsShort)) ? monthsShort : undefined, weekdaysFull: (angular.isDefined(weekdaysFull)) ? weekdaysFull : undefined, weekdaysShort: (angular.isDefined(weekdaysShort)) ? weekdaysShort : undefined, weekdaysLetter: (angular.isDefined(weekdaysLetter)) ? weekdaysLetter : undefined, firstDay: (angular.isDefined(scope.firstDay)) ? scope.firstDay : 0, disable: (angular.isDefined(scope.disable)) ? scope.disable : undefined, today: (angular.isDefined(scope.today)) ? scope.today : undefined, clear: (angular.isDefined(scope.clear)) ? scope.clear : undefined, close: (angular.isDefined(scope.close)) ? scope.close : undefined, selectYears: (angular.isDefined(scope.selectYears)) ? scope.selectYears : undefined, selectMonths: (angular.isDefined(scope.selectMonths)) ? scope.selectMonths : undefined, onStart: (angular.isDefined(scope.onStart)) ? function(){ scope.onStart(); } : undefined, onRender: (angular.isDefined(scope.onRender)) ? function(){ scope.onRender(); } : undefined, onOpen: (angular.isDefined(scope.onOpen)) ? function(){ scope.onOpen(); } : undefined, onClose: (angular.isDefined(scope.onClose)) ? function(){ scope.onClose(); } : undefined, onSet: (angular.isDefined(scope.onSet)) ? function(){ scope.onSet(); } : undefined, onStop: (angular.isDefined(scope.onStop)) ? function(){ scope.onStop(); } : undefined }; if (!scope.container) { delete options.container; } var pickadateInput = element.pickadate(options); //pickadate API var picker = pickadateInput.pickadate('picker'); //watcher of min, max, and disabled dates scope.$watch('max', function(newMax) { if( picker ) { var maxDate = new Date(newMax); picker.set({max: isValidDate(maxDate) ? maxDate : false}); } }); scope.$watch('min', function(newMin) { if( picker ) { var minDate = new Date(newMin); picker.set({min: isValidDate(minDate) ? minDate : false}); } }); scope.$watch('disable', function(newDisabled) { if( picker ) { var disabledDates = angular.isDefined(newDisabled) && angular.isArray(newDisabled) ? newDisabled : false; picker.set({disable: disabledDates}); } }); }); } } }; }]); /** * time-picker directive * Example: <label for="input_starttime">Time</label> <input id="input_starttime" input-clock data-twelvehour="false" type="text"> */ angular.module("ui.materialize.input_clock", []) .directive('inputClock', [function () { return { restrict: 'A', scope: { default: "@", fromnow: "=?", donetext: "@", autoclose: "=?", ampmclickable: "=?", darktheme: "=?", twelvehour: "=?", vibrate: "=?" }, link: function (scope, element) { $(element).addClass("timepicker"); if (!(scope.ngReadonly)) { element.pickatime({ default: (angular.isDefined(scope.default)) ? scope.default : '', fromnow: (angular.isDefined(scope.fromnow)) ? scope.fromnow : 0, donetext: (angular.isDefined(scope.donetext)) ? scope.donetext : 'Done', autoclose: (angular.isDefined(scope.autoclose)) ? scope.autoclose : false, ampmclickable: (angular.isDefined(scope.ampmclickable)) ? scope.ampmclickable : false, darktheme: (angular.isDefined(scope.darktheme)) ? scope.darktheme : false, twelvehour: (angular.isDefined(scope.twelvehour)) ? scope.twelvehour : true, vibrate: (angular.isDefined(scope.vibrate)) ? scope.vibrate : true }); } } }; }]); /** * Example: <pagination page="1" page-size="10" total="100" pagination-action="changePage(page)" ul-class="customClass"> * ul-class could be either an object or a string * * Based on https://github.com/brantwills/Angular-Paging */ angular.module("ui.materialize.pagination", []) .directive('pagination', ["$sce", function ($sce) { // Assign null-able scope values from settings function setScopeValues(scope, attrs) { scope.List = []; scope.Hide = false; scope.page = parseInt(scope.page) || 1; scope.total = parseInt(scope.total) || 0; scope.dots = scope.dots || '...'; scope.ulClass = scope.ulClass || attrs.ulClass || 'pagination'; scope.adjacent = parseInt(scope.adjacent) || 2; scope.activeClass = 'active'; scope.disabledClass = 'disabled'; scope.scrollTop = scope.$eval(attrs.scrollTop); scope.hideIfEmpty = scope.$eval(attrs.hideIfEmpty); scope.showPrevNext = scope.$eval(attrs.showPrevNext); scope.useSimplePrevNext = scope.$eval(attrs.useSimplePrevNext); } // Validate and clean up any scope values // This happens after we have set the // scope values function validateScopeValues(scope, pageCount) { // Block where the page is larger than the pageCount if (scope.page > pageCount) { scope.page = pageCount; } // Block where the page is less than 0 if (scope.page <= 0) { scope.page = 1; } // Block where adjacent value is 0 or below if (scope.adjacent <= 0) { scope.adjacent = 2; } // Hide from page if we have 1 or less pages // if directed to hide empty if (pageCount <= 1) { scope.Hide = scope.hideIfEmpty; } } // Internal Pagination Click Action function internalAction(scope, page) { page = page.valueOf(); // Block clicks we try to load the active page if (scope.page == page) { return; } // Update the page in scope and fire any paging actions scope.page = page; scope.paginationAction({ page: page }); // If allowed scroll up to the top of the page if (scope.scrollTop) { scrollTo(0, 0); } } // Add Range of Numbers function addRange(start, finish, scope) { var i = 0; for (i = start; i <= finish; i++) { var item = { value: $sce.trustAsHtml(i.toString()), liClass: scope.page == i ? scope.activeClass : 'waves-effect', action: function() { internalAction(scope, this.value); } }; scope.List.push(item); } } // Add Dots ie: 1 2 [...] 10 11 12 [...] 56 57 function addDots(scope) { scope.List.push({ value: $sce.trustAsHtml(scope.dots) }); } // Add First Pages function addFirst(scope, next) { addRange(1, 2, scope); // We ignore dots if the next value is 3 // ie: 1 2 [...] 3 4 5 becomes just 1 2 3 4 5 if (next != 3) { addDots(scope); } } /** * Add the first, previous, next, and last buttons if desired * The logic is defined by the mode of interest * This method will simply return if the scope.showPrevNext is false * This method will simply return if there are no pages to display * * @param {Object} scope - The local directive scope object * @param {int} pageCount - The last page number or total page count * @param {string} mode - The mode of interest either prev or last */ function addPrevNext(scope, pageCount, mode){ // Ignore if we are not showing // or there are no pages to display if (!scope.showPrevNext || pageCount < 1) { return; } // Local variables to help determine logic var disabled, alpha, beta; // Determine logic based on the mode of interest // Calculate the previous / next page and if the click actions are allowed if(mode === 'prev') { disabled = scope.page - 1 <= 0; var prevPage = scope.page - 1 <= 0 ? 1 : scope.page - 1; if (scope.useSimplePrevNext) { alpha = {value: "<<", title: 'First Page', page: 1}; beta = {value: "<", title: 'Previous Page', page: prevPage }; } else { alpha = {value: "<i class=\"material-icons\">first_page</i>", title: 'First Page', page: 1}; beta = {value: "<i class=\"material-icons\">chevron_left</i>", title: 'Previous Page', page: prevPage }; } } else { disabled = scope.page + 1 > pageCount; var nextPage = scope.page + 1 >= pageCount ? pageCount : scope.page + 1; if (scope.useSimplePrevNext) { alpha = { value : ">", title: 'Next Page', page: nextPage }; beta = { value: ">>", title: 'Last Page', page: pageCount }; } else { alpha = { value : "<i class=\"material-icons\">chevron_right</i>", title: 'Next Page', page: nextPage }; beta = { value: "<i class=\"material-icons\">last_page</i>", title: 'Last Page', page: pageCount }; } } // Create the Add Item Function var addItem = function(item, disabled){ scope.List.push({ value: $sce.trustAsHtml(item.value), title: item.title, liClass: disabled ? scope.disabledClass : '', action: function(){ if(!disabled) { internalAction(scope, item.page); } } }); }; // Add our items addItem(alpha, disabled); addItem(beta, disabled); } function addLast(pageCount, scope, prev) { // We ignore dots if the previous value is one less that our start range // ie: 1 2 3 4 [...] 5 6 becomes just 1 2 3 4 5 6 if (prev != pageCount -2) { addDots(scope); } addRange(pageCount -1, pageCount, scope); } // Main build function function build(scope, attrs) { // Block divide by 0 and empty page size if (!scope.pageSize || scope.pageSize < 0) { return; } // Assign scope values setScopeValues(scope, attrs); // local variables var start, size = scope.adjacent * 2, pageCount = Math.ceil(scope.total / scope.pageSize); // Validation Scope validateScopeValues(scope, pageCount); // Add the Next and Previous buttons to our list addPrevNext(scope, pageCount, 'prev'); if (pageCount < (5 + size)) { start = 1; addRange(start, pageCount, scope); } else { var finish; if (scope.page <= (1 + size)) { start = 1; finish = 2 + size + (scope.adjacent - 1); addRange(start, finish, scope); addLast(pageCount, scope, finish); } else if (pageCount - size > scope.page && scope.page > size) { start = scope.page - scope.adjacent; finish = scope.page + scope.adjacent; addFirst(scope, start); addRange(start, finish, scope); addLast(pageCount, scope, finish); } else { start = pageCount - (1 + size + (scope.adjacent - 1)); finish = pageCount; addFirst(scope, start); addRange(start, finish, scope); } } addPrevNext(scope, pageCount, 'next'); } return { restrict: 'EA', scope: { page: '=', pageSize: '=', total: '=', dots: '@', hideIfEmpty: '@', adjacent: '@', scrollTop: '@', showPrevNext: '@', useSimplePrevNext: '@', paginationAction: '&', ulClass: '=?' }, template: '<ul ng-hide="Hide" ng-class="ulClass"> ' + '<li ' + 'ng-class="Item.liClass" ' + 'ng-click="Item.action()" ' + 'ng-repeat="Item in List"> ' + '<a href> ' + '<span ng-bind-html="Item.value"></span> ' + '</a>' + '</ul>', link: function (scope, element, attrs) { // Hook in our watched items scope.$watchCollection('[page, total, pageSize]', function () { build(scope, attrs); }); } }; }]); /* example usage: <!-- Modal Trigger --> <a class='btn' data-target='demoModal' modal>show Modal</a> <!-- Modal Structure --> <div id="demoModal" class="modal"> <div class="modal-content"> <h4>Modal Header</h4> <p>A bunch of text</p> </div> <div class="modal-footer"> <a href="#!" class=" modal-action modal-close waves-effect waves-green btn-flat">Agree</a> </div> </div> */ angular.module("ui.materialize.modal", []) .directive("modal", ["$compile", "$timeout", function ($compile, $timeout) { return { scope: { dismissible: "=", opacity: "@", inDuration: "@", outDuration: "@", startingTop: "@", endingTop: "@", ready: '&?', complete: '&?', open: '=?', enableTabs: '@?' }, link: function (scope, element, attrs) { $timeout(function () { var modalEl = $(attrs.href ? attrs.href : '#' + attrs.target); $compile(element.contents())(scope); var complete = function () { angular.isFunction(scope.complete) && scope.$apply(scope.complete); scope.open = false; scope.$apply(); }; var ready = function() { angular.isFunction(scope.ready) && scope.$apply(scope.ready); // Need to keep open boolean in sync. scope.open = true; scope.$apply(); // If tab support is enabled we need to re-init the tabs // See https://github.com/Dogfalo/materialize/issues/1634 if (scope.enableTabs) { modalEl.find('ul.tabs').tabs(); } }; var options = { dismissible: (angular.isDefined(scope.dismissible)) ? scope.dismissible : undefined, opacity: (angular.isDefined(scope.opacity)) ? scope.opacity : undefined, inDuration: (angular.isDefined(scope.inDuration)) ? scope.inDuration : undefined, outDuration: (angular.isDefined(scope.outDuration)) ? scope.outDuration : undefined, startingTop: (angular.isDefined(scope.startingTop)) ? scope.startingTop : undefined, endingTop: (angular.isDefined(scope.endingTop)) ? scope.endingTop : undefined, ready: ready, complete: complete, }; modalEl.modal(options); element.modal(options); // Setup watch for opening / closing modal programatically. if (angular.isDefined(attrs.open) && modalEl.length > 0) { scope.$watch('open', function(value, lastValue) { if (!angular.isDefined(value)) { return; } (value === true) ? modalEl.modal('open') : modalEl.modal('close'); }); } }); } }; }]); /* example usage: <!-- data-position can be : bottom, top, left, or right --> <!-- data-delay controls delay before tooltip shows (in milliseconds)--> <a class="btn" tooltipped data-position="bottom" data-delay="50" data-tooltip="I am tooltip">Hover me!</a> */ angular.module("ui.materialize.tooltipped", []) .directive("tooltipped", ["$compile", "$timeout", function ($compile, $timeout) { return { restrict: "A", link: function (scope, element, attrs) { var rmDestroyListener = Function.prototype; //assigning to noop function init() { element.addClass("tooltipped"); $compile(element.contents())(scope); $timeout(function () { // https://github.com/Dogfalo/materialize/issues/3546 // if element.addClass("tooltipped") would not be executed, then probably this would not be needed if (element.attr('data-tooltip-id')){ element.tooltip('remove'); } element.tooltip(); }); rmDestroyListener = scope.$on('$destroy', function () { element.tooltip("remove"); }); } attrs.$observe('tooltipped', function (value) { if (value === 'false' && rmDestroyListener !== Function.prototype) { element.tooltip("remove"); rmDestroyListener(); rmDestroyListener = Function.prototype; } else if (value !== 'false' && rmDestroyListener === Function.prototype) { init(); } }); if (attrs.tooltipped !== 'false') { init(); } // just to be sure, that tooltip is removed when somehow element is destroyed, but the parent scope is not element.on('$destroy', function() { element.tooltip("remove"); }); scope.$watch(function () { return element.attr('data-tooltip'); }, function (oldVal, newVal) { if (oldVal !== newVal && attrs.tooltippify !== 'false') { $timeout(function () { element.tooltip(); }); } }); } }; }]); /* example usage: <!-- normal materialboxed --> <img materialboxed class="materialboxed responsive-img" width="650" src="images/sample-1.jpg"> <!-- caption materialboxed --> <img materialboxed class="materialboxed" data-caption="A picture of some deer and tons of trees" width="250" src="iamges/nature_portrait_by_pw_fotografie-d63tx0n.jpg"> */ angular.module("ui.materialize.materialboxed", []) .directive("materialboxed", ["$timeout", function($timeout){ return { restrict: 'A', link: function(scope, element, attrs) { $timeout(function(){ element.materialbox(); }); } }; }]); /* example usage: In controller: $scope.value = [30]; $scope.value = 30; $scope.value = [30, 40]; <div nouislider ng-model='value' min="0" max="100"></div> <div nouislider ng-model='value' connect="lower" min="0" max="100"></div> (green) bar beetwen one handle <div nouislider ng-model='value' connect="true" min="0" max="100"></div> (green) bar beetwen handles */ angular.module("ui.materialize.nouislider", []) .directive("nouislider", ["$timeout", function($timeout){ return { restrict: 'A', scope: { ngModel: '=', min: '@', max: '@', step: '@?', connect: '@?', tooltips: '@?', behaviour: '@?' }, link: function (scope, element, attrs) { var modelIsArray = false; var watchNgModel = scope.$watch('ngModel', function(newValue) { if (newValue !== undefined) { createNoUiSlider(); watchNgModel(); } }); element[0].noUiSlider.on('update', function(values, input) { $timeout(function() { scope.ngModel = modelIsArray ? values : values[0]; }); }); function createNoUiSlider() { if (angular.isArray(scope.ngModel)) { modelIsArray = true; } noUiSlider.create(element[0], { start: scope.ngModel || 0, step: parseFloat(scope.step || 1), tooltips: angular.isDefined(scope.tooltips) ? scope.tooltips : undefined, connect: angular.isDefined(scope.connect) ? scope.connect : [false, false], behaviour: angular.isDefined(scope.behaviour) ? scope.behaviour : undefined, range: { 'min': parseFloat(scope.min || 0), 'max': parseFloat(scope.max || 100), }, format: { to: function (number) { return Math.round(number * 100) / 100; }, from: function (number) { return Number(number); } } }); function getConnection(value) { value.toLowerCase(); if ('true' === value || 'false' === value) { return JSON.parse(value); } return value; } }; } }; }]); }(angular));