1//referenced from this link: http://www.aaronkjackson.com/2012/04/formatting-dates-with-knockoutjs/ 2ko.bindingHandlers.dateString = { 3 update: function (element, valueAccessor, allBindingsAccessor, viewModel) { 4 var value = valueAccessor(); 5 var allBindings = allBindingsAccessor(); 6 var valueUnwrapped = ko.utils.unwrapObservable(value); 7 8 var dateUnwrapped = new Date(valueUnwrapped); 9 valueUnwrapped = moment(dateUnwrapped).toISOString(); 10 11 var pattern = allBindings.datePattern || 'MM/dd/yyyy'; 12 //allBindings.value(moment(valueUnwrapped).format(pattern)); //Under some condition, allBindings.value would be undefined. 13 if (valueUnwrapped !== null && valueUnwrapped !== undefined && valueUnwrapped.length > 0 && valueUnwrapped !== "Invalid date") { 14 $(element).val(moment(valueUnwrapped).format(pattern)); 15 } 16 //Remove the "else" since we allow user to type date in text field. 17 } 18}; 19 20ko.bindingHandlers.datetimePicker = { 21 init: function (element, valueAccessor) { 22 var value = valueAccessor(); 23 $(element).datetimepicker({ 24 format: 'mm/dd/yyyy', 25 weekStart: 1, 26 todayBtn: 'linked', 27 autoclose: true, 28 todayHighlight: 1, 29 startView: 2, 30 minView: 2, 31 forceParse: 0, 32 bootcssVer: 3 33 }).on('changeDate', function (ev) { 34 value(ev.date); 35 }); 36 }, 37 update: function (element, valueAccessor) { 38 var value = valueAccessor(); 39 $(element).val(new Date(ko.unwrap(value)).format('MM/dd/yyyy')); 40 } 41}; 42 43ko.bindingHandlers.tagsInput = { 44 init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { 45 var value = valueAccessor() 46 var options = allBindingsAccessor(); 47 options = Object.assign({}, { 48 freeInput: false, 49 param: "", 50 itemText: function (item) { 51 return item.Name; 52 }, 53 itemValue: function (item) { 54 return item.Id; 55 } 56 }, options); 57 58 $(element).tagsinput({ 59 freeInput: options.freeInput, 60 confirmKeys: [13, 44, 59], 61 itemText: options.itemText, 62 itemValue: options.itemValue, 63 trimValue: true, 64 typeahead: { 65 items: 5, 66 source: typeof options.sourceHandler === 'function' ? options.sourceHandler : 67 typeof options.sourceHandler === 'string' ? function (query) { 68 return $.stormstorecrud($.stormstoreservice('/' + options.sourceHandler, 'QueryByName'), 'GET', String.format("query={0}{1}", query, options.param)); 69 } : 70 options.sourceHandler instanceof Array ? options.sourceHandler : [] 71 } 72 }); 73 74 var handler = function (event) { value($(event.target).tagsinput('items')); }; 75 $(element).on('itemAdded', handler).on('itemRemoved', handler); 76 77 (ko.toJS(value) || []).forEach(function (item) { 78 $(element).tagsinput("add", item); 79 }); 80 } 81}; 82 83//http://knockoutjs.com/documentation/fn.html 84//This method is to filter the current array with specified value. 85ko.observableArray.fn.filterByProperty = function (propName, matchValue) { 86 87 return ko.pureComputed(function () { 88 89 var allItems = this(), 90 matchingItems = []; 91 92 for (var i = 0; i < allItems.length; i++) { 93 var current = allItems[i]; 94 if (ko.unwrap(current[propName]) === matchValue) 95 matchingItems.push(current); 96 } 97 98 return matchingItems; 99 }, this); 100} 101 102 103ko.extenders.numeric = function (target, precision) { 104 //create a writable computed observable to intercept writes to our observable 105 var result = ko.pureComputed({ 106 read: target, //always return the original observables value 107 write: function (newValue) { 108 var current = target(), 109 roundingMultiplier = Math.pow(10, precision), 110 newValueAsNum = isNaN(newValue) ? 0 : +newValue, 111 valueToWrite = Math.round(newValueAsNum * roundingMultiplier) / roundingMultiplier; 112 113 //only write if it changed 114 if (valueToWrite !== current) { 115 target(valueToWrite); 116 } else { 117 //if the rounded value is the same, but a different value was written, force a notification for the current field 118 if (newValue !== current) { 119 target.notifySubscribers(valueToWrite); 120 } 121 } 122 } 123 }).extend({ notify: 'always' });
124 125 //initialize with current value to make sure it is rounded appropriately 126 result(target()); 127 128 //return the new computed observable 129 return result; 130}; 131 132ko.extenders.range = function (target, intRange) { 133 //create a writeable computed observable to intercept writes to our observable 134 var result = ko.computed({ 135 read: target, //always return the original observables value 136 write: function (newValue) { 137 var current = target(), 138 newValueAsNum = isNaN(newValue) ? 0 : parseInt(+newValue, 10), 139 valueToWrite = newValueAsNum; 140 141 if (newValueAsNum < intRange.min) { 142 valueToWrite = intRange.min; 143 } 144 145 if (newValueAsNum > intRange.max) { 146 valueToWrite = intRange.max; 147 } 148 //only write if it changed 149 if (valueToWrite !== current) { 150 target(valueToWrite); 151 } else { 152 //if the tested value is the same, but a different value was written, force a notification for the current field 153 if (newValue !== current) { 154 target.notifySubscribers(valueToWrite); 155 } 156 } 157 } 158 }).extend({ notify: 'always' }); 159 160 //initialize with current value to make sure it is rounded appropriately 161 result(target()); 162 163 //return the new computed observable 164 return result; 165}; 166ko.bindingHandlers.masked = { 167 init: function (element, valueAccessor, allBindingsAccessor) { 168 var mask = allBindingsAccessor().mask || {}; 169 $(element).mask(mask, { placeholder: mask }); 170 ko.utils.registerEventHandler(element, 'focusout', function () { 171 var observable = valueAccessor(); 172 observable($(element).cleanVal()); 173 }); 174 }, 175 update: function (element, valueAccessor) { 176 var value = ko.utils.unwrapObservable(valueAccessor()); 177 $(element).val($(element).masked(value)); 178 } 179}; 180// From StackOverflow: https://stackoverflow.com/questions/47203657/select2-4-x-and-knockoutjs 181ko.bindingHandlers.select2 = { 182 init: function (el, valueAccessor, allBindingsAccessor, viewModel) { 183 ko.utils.domNodeDisposal.addDisposeCallback(el, function () { 184 $(el).select2('destroy'); 185 }); 186 187 var allBindings = allBindingsAccessor(), 188 select2 = ko.utils.unwrapObservable(allBindings.select2); 189 if (select2.remote) { 190 $(el).append('<option value></option>'); 191 $(el).select2({ 192 ajax: { 193 url: globalConfig.baseUrl + select2.url, 194 dataType: 'json', 195 delay: 250, 196 data: function (params) { 197 var parameters = { 198 query: params.term || '' // search term 199 }; 200 201 if (select2.params !== undefined) { 202 $.each(Object.keys(select2.params), function (index, value) { 203 parameters[value] = select2.params[value](); 204 }) 205 } 206 return parameters; 207 }, 208 processResults: function (data, params) { 209 210 // parse the results into the format expected by Select2 211 // since we are using custom formatting functions we do not need to 212 // alter the remote JSON data, except to indicate that infinite 213 // scrolling can be used 214 params.page = params.page || 1; 215 var result = []; 216 $.each(data, function (index, value) { 217 result.push({ id: value.Id, text: value.Name }) 218 }) 219 return { 220 results: result, 221 //pagination: { 222 // more: (params.page * 30) < data.total_count 223 //} 224 }; 225 }, 226 cache: true 227 }, 228 escapeMarkup: function (markup) { return markup; }, // let our custom formatter work 229 placeholder: select2.placeholder, 230 allowClear: select2.allowClear 231 }); 232 } 233 else { 234 $(el).select2(select2); 235 } 236 }, 237 update: function (el, valueAccessor, allBindingsAccessor, viewModel) { 238 var allBindings = allBindingsAccessor(); 239 if ("value" in allBindings) { 240 if ((allBindings.select2.multiple || el.multiple) && allBindings.value(
240) && allBindings.value().constructor != Array) { 241 $(el).val(allBindings.value().split(',')).trigger('change'); 242 } 243 else { 244 $(el).val(allBindings.value()).trigger('change'); 245 } 246 } else if ("selectedOptions" in allBindings) { 247 var converted = []; 248 var textAccessor = function (value) { return value; }; 249 if ("optionsText" in allBindings) { 250 textAccessor = function (value) { 251 var valueAccessor = function (item) { return item; } 252 if ("optionsValue" in allBindings) { 253 valueAccessor = function (item) { return item[allBindings.optionsValue]; } 254 } 255 var items = $.grep(allBindings.options(), function (e) { return valueAccessor(e) == value }); 256 if (items.length == 0 || items.length > 1) { 257 return "UNKNOWN"; 258 } 259 return items[0][allBindings.optionsText]; 260 } 261 } 262 $.each(allBindings.selectedOptions(), function (key, value) { 263 converted.push({ id: value, text: textAccessor(value) }); 264 }); 265 $(el).select2("data", converted); 266 } 267 $(el).trigger("change"); 268 } 269};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.