Everyday is a new day with Symfony, but I'm loving it!
This morning I installed the sfJQueryUIPlugin. It has very little dependencies & accepts themeRoller styles. However, it has 2 issues:
[Feature_Request] There is no way to specify the year range. By default, it shows a 20 year range around the year in the field value. eg. if field value is 1993-01-20, the range will be 1983 to 2003.
??? Has anyone found a way out???
The DatePicker does not appear when the field is empty, Thus it does not show up during new record creation.
To solve this, I tried setting up the default value in the date input field (which now appears as a text input) using $this->setDefault('date_of_birth',date('Y-m-d'));
??? Is anybody facing this problem of picker now available during new record creation ???
??? Also is it the right way to set default value ???
Thanks in advance.
To get the date picker on the new registration form, I had to include javascripts in the indexSuccess template of my form (my fault)
as for the year range, I modified the plugin file to include additional parameter
class sfWidgetFormDateJQueryUI extends sfWidgetForm
{
protected function configure($options = array(), $attributes = array())
{
if(sfContext::hasInstance())
$this->addOption('culture', sfContext::getInstance()->getUser()->getCulture());
else
$this->addOption('culture', "en");
$this->addOption('change_month', false);
$this->addOption('change_year', false);
$this->addOption('number_of_months', 1);
$this->addOption('show_button_panel', false);
$this->addOption('theme', '/sfJQueryUIPlugin/css/ui-lightness/jquery-ui.css');
$this->addOption('year_range', '-30:+0');
parent::configure($options, $attributes);
}
public function render($name, $value = null, $attributes = array(), $errors = array())
{
$attributes = $this->getAttributes();
$input = new sfWidgetFormInput(array(), $attributes);
$html = $input->render($name, $value);
$id = $input->generateId($name);
$culture = $this->getOption('culture');
$cm = $this->getOption("change_month") ? "true" : "false";
$cy = $this->getOption("change_year") ? "true" : "false";
$nom = $this->getOption("number_of_months");
$sbp = $this->getOption("show_button_panel") ? "true" : "false";
$yrs = $this->getOption("year_range");
if ($culture!='en')
{
$html .= <<<EOHTML
<script type="text/javascript">
$(function() {
var params = $.datepicker.regional['$culture'];
params.changeMonth = $cm;
params.changeYear = $cy;
params.numberOfMonths = $nom;
params.showButtonPanel = $sbp;
params.yearRange = "$yrs";
$("#$id").datepicker(params);
});
</script>
EOHTML;
}
else
{
$html .= <<<EOHTML
<script type="text/javascript">
$(function() {
var params = {
changeMonth : $cm,
changeYear : $cy,
numberOfMonths : $nom,
showButtonPanel : $sbp,
yearRange : "$yrs"
};
$("#$id").datepicker(params);
});
</script>
EOHTML;
}
return $html;
}
public function getStylesheets()
{...
}
public function getJavaScripts()
{...
}
}
and setup the widget as:
$this->widgetSchema['date_of_birth']= new sfWidgetFormDateJQueryUI(array("change_month" => true, "change_year" => true, "theme" => "smoothness/jquery-ui-1.8.custom.css", "year_range" => "-30:+0"));
Related
I am using kendo ui grid which have custom filter for all date columns. I used custom date filter because I want to sent date in "yyyy-MM-dd" format while filtering. My grid operated completely server side for paging and filters as well.
Below is the kendo code in MVC which I had used for date column -
columns.Bound(p => p.CreatedOn).Title("Created On").Width("5%").Format("{0:dd/MM/yyyy}").Filterable(filterable => filterable
.Extra(false).UI("CreatedOnFilter"));
And here is my script used for it -
function CreatedOnFilter(e) {
e.kendoDatePicker({
format: "dd/MM/yyyy",
change: function () {
debugger;
var ds = $("#InvoiceGrid").data().kendoGrid.dataSource;
var nd = new Date(this.value());
var day = ("0" + nd.getDate()).slice(-2);
var mnth = ("0" + (nd.getMonth() + 1)).slice(-2);
var formattedDate = [nd.getFullYear(), mnth, day].join("-");
var curr_filters;
if(ds.filter() != undefined){
curr_filters = ds.filter().filters;
var new_filter = {
"filters": [
{
"field": "CreatedOn",
"operator": "contains",///Here is where I want operator as selected by user.
"value": formattedDate
}
]
};
curr_filters.push(new_filter);
}
else{
var new_filter = {
"filters": [
{
"field": "CreatedOn",
"operator": "contains",///Here is where I want operator as selected by user.
"value": formattedDate
}
]
};
curr_filters = new_filter;
}
ds.filter(curr_filters);
this.element.closest("form").data().kendoPopup.close();
// kendo.ui.progress($('#divInvoiceList'), false);
}
});
}
As shown in above code script. In operator I want it to be as selected by user.
Any help will be highly appreciated.
This is how I use in columns
{
field : "ReceivedDate",
title : "Date Received",
template : "#= kendo.toString(kendo.parseDate(ReceivedDate, 'yyyy-MM-dd'), 'MM/dd/yyyy') #",
filterable : {
cell : {
showOperators : false,
operator : "eq",
template : function(args) {
args.element.kendoDatePicker({
format : "MM/dd/yyyy"
});
}
}
}
},
template is used to change the format that I receive from server.
I'm looking for a way to show document type alias or name of selected content in Multinode tree picker inside content tab.
This will tremendously help me to quickly identify type of content attached. Also hovering a content added in MNTP inside content shows numeric path which is not quite useful, is there a way to show path names instead of id's?
Attaching image for reference.
Kindly suggest.
The easiest way to do this is to simply modify the MNTP property editor and have it show the extra data. It is however not really recommended to modify these files since it will be reverted every time you upgrade your Umbraco site.
There is a bit of a hacky workaround to achieve what you want however;
Angular has something called interceptors, allowing you to intercept and modify requests being made. By registrering an interceptor you could intercept the requests to contentpicker.html and redirect it to a contentpicker.html file located somewhere else - this means you will be able to just copy this file somewhere else and not modify the one in the umbraco folder being overwritten by upgrades.
Unfortunately in this case it isn't enough to just override the view being sent to the browser, since the document type alias is not actually available to that view - so the view would never be able to show the alias even if we modified it.
To work around that, you could create a copy of the contentpicker.controller.js file and create a modified version of that to use in your custom contentpicker.html view. This modified ContentPickerController would make sure to include the contentTypeAlias in the model being used in rendering the view.
All of this can be wrapped up as a "package" in the App_Plugins folder and it will be nicely separated away from being overwritten when you upgrade Umbraco, while being automatically loaded via the package.manifest file. The only caveat is that in case something is updated in the content picker code, you would have to manually merge those updates over into your custom content picker files - fortunately the content picker is rarely updated.
Place the following files in App_Plugins/CustomContentPicker/ folder and you should have what you want without actually modifying the core code:
package.manifest
{
"javascript": [
"~/App_Plugins/CustomContentPicker/customcontentpicker.controller.js"
]
}
customcontentpicker.html
<div ng-controller="Umbraco.PropertyEditors.CustomContentPickerController" class="umb-editor umb-contentpicker">
<ng-form name="contentPickerForm">
<ul class="unstyled list-icons"
ui-sortable
ng-model="renderModel">
<li ng-repeat="node in renderModel" ng-attr-title="{{model.config.showPathOnHover && 'Path: ' + node.path || undefined}}">
<i class="icon icon-navigation handle"></i>
<a href="#" prevent-default ng-click="remove($index)">
<i class="icon icon-delete red hover-show"></i>
<i class="{{node.icon}} hover-hide"></i>
{{node.name}}<br />
({{node.contentTypeAlias}})
</a>
<div ng-if="!dialogEditor && ((model.config.showOpenButton && allowOpenButton) || (model.config.showEditButton && allowEditButton))">
<small ng-if="model.config.showOpenButton && allowOpenButton"><a href ng-click="showNode($index)"><localize key="open">Open</localize></a></small>
<small ng-if="model.config.showEditButton && allowEditButton"><a href umb-launch-mini-editor="node"><localize key="edit">Edit</localize></a></small>
</div>
</li>
</ul>
<ul class="unstyled list-icons" ng-show="model.config.multiPicker === true || renderModel.length === 0">
<li>
<i class="icon icon-add blue"></i>
<a href="#" ng-click="openContentPicker()" prevent-default>
<localize key="general_add">Add</localize>
</a>
</li>
</ul>
<!--These are here because we need ng-form fields to validate against-->
<input type="hidden" name="minCount" ng-model="renderModel" />
<input type="hidden" name="maxCount" ng-model="renderModel" />
<div class="help-inline" val-msg-for="minCount" val-toggle-msg="minCount">
You need to add at least {{model.config.minNumber}} items
</div>
<div class="help-inline" val-msg-for="maxCount" val-toggle-msg="maxCount">
You can only have {{model.config.maxNumber}} items selected
</div>
</ng-form>
<umb-overlay
ng-if="contentPickerOverlay.show"
model="contentPickerOverlay"
view="contentPickerOverlay.view"
position="right">
</umb-overlay>
</div>
customcontentpicker.controller.js
angular.module('umbraco.services').config([
'$httpProvider',
function ($httpProvider) {
$httpProvider.interceptors.push(function ($q) {
return {
'request': function (request) {
var url = 'views/propertyeditors/contentpicker/contentpicker.html';
if (request.url.indexOf(url) !== -1) {
request.url = request.url.replace(url, '/App_Plugins/CustomContentPicker/customcontentpicker.html');
}
return request || $q.when(request);
}
};
});
}]);
// Below is contentpicker.controller.js modified
//this controller simply tells the dialogs service to open a mediaPicker window
//with a specified callback, this callback will receive an object with a selection on it
function customContentPickerController($scope, dialogService, entityResource, editorState, $log, iconHelper, $routeParams, fileManager, contentEditingHelper, angularHelper, navigationService, $location) {
function trim(str, chr) {
var rgxtrim = (!chr) ? new RegExp('^\\s+|\\s+$', 'g') : new RegExp('^' + chr + '+|' + chr + '+$', 'g');
return str.replace(rgxtrim, '');
}
function startWatch() {
//We need to watch our renderModel so that we can update the underlying $scope.model.value properly, this is required
// because the ui-sortable doesn't dispatch an event after the digest of the sort operation. Any of the events for UI sortable
// occur after the DOM has updated but BEFORE the digest has occured so the model has NOT changed yet - it even states so in the docs.
// In their source code there is no event so we need to just subscribe to our model changes here.
//This also makes it easier to manage models, we update one and the rest will just work.
$scope.$watch(function () {
//return the joined Ids as a string to watch
return _.map($scope.renderModel, function (i) {
return i.id;
}).join();
}, function (newVal) {
var currIds = _.map($scope.renderModel, function (i) {
return i.id;
});
$scope.model.value = trim(currIds.join(), ",");
//Validate!
if ($scope.model.config && $scope.model.config.minNumber && parseInt($scope.model.config.minNumber) > $scope.renderModel.length) {
$scope.contentPickerForm.minCount.$setValidity("minCount", false);
}
else {
$scope.contentPickerForm.minCount.$setValidity("minCount", true);
}
if ($scope.model.config && $scope.model.config.maxNumber && parseInt($scope.model.config.maxNumber) < $scope.renderModel.length) {
$scope.contentPickerForm.maxCount.$setValidity("maxCount", false);
}
else {
$scope.contentPickerForm.maxCount.$setValidity("maxCount", true);
}
});
}
$scope.renderModel = [];
$scope.dialogEditor = editorState && editorState.current && editorState.current.isDialogEditor === true;
//the default pre-values
var defaultConfig = {
multiPicker: false,
showOpenButton: false,
showEditButton: false,
showPathOnHover: false,
startNode: {
query: "",
type: "content",
id: $scope.model.config.startNodeId ? $scope.model.config.startNodeId : -1 // get start node for simple Content Picker
}
};
if ($scope.model.config) {
//merge the server config on top of the default config, then set the server config to use the result
$scope.model.config = angular.extend(defaultConfig, $scope.model.config);
}
//Umbraco persists boolean for prevalues as "0" or "1" so we need to convert that!
$scope.model.config.multiPicker = ($scope.model.config.multiPicker === "1" ? true : false);
$scope.model.config.showOpenButton = ($scope.model.config.showOpenButton === "1" ? true : false);
$scope.model.config.showEditButton = ($scope.model.config.showEditButton === "1" ? true : false);
$scope.model.config.showPathOnHover = ($scope.model.config.showPathOnHover === "1" ? true : false);
var entityType = $scope.model.config.startNode.type === "member"
? "Member"
: $scope.model.config.startNode.type === "media"
? "Media"
: "Document";
$scope.allowOpenButton = entityType === "Document" || entityType === "Media";
$scope.allowEditButton = entityType === "Document";
//the dialog options for the picker
var dialogOptions = {
multiPicker: $scope.model.config.multiPicker,
entityType: entityType,
filterCssClass: "not-allowed not-published",
startNodeId: null,
callback: function (data) {
if (angular.isArray(data)) {
_.each(data, function (item, i) {
$scope.add(item);
});
} else {
$scope.clear();
$scope.add(data);
}
angularHelper.getCurrentForm($scope).$setDirty();
},
treeAlias: $scope.model.config.startNode.type,
section: $scope.model.config.startNode.type
};
//since most of the pre-value config's are used in the dialog options (i.e. maxNumber, minNumber, etc...) we'll merge the
// pre-value config on to the dialog options
angular.extend(dialogOptions, $scope.model.config);
//We need to manually handle the filter for members here since the tree displayed is different and only contains
// searchable list views
if (entityType === "Member") {
//first change the not allowed filter css class
dialogOptions.filterCssClass = "not-allowed";
var currFilter = dialogOptions.filter;
//now change the filter to be a method
dialogOptions.filter = function (i) {
//filter out the list view nodes
if (i.metaData.isContainer) {
return true;
}
if (!currFilter) {
return false;
}
//now we need to filter based on what is stored in the pre-vals, this logic duplicates what is in the treepicker.controller,
// but not much we can do about that since members require special filtering.
var filterItem = currFilter.toLowerCase().split(',');
var found = filterItem.indexOf(i.metaData.contentType.toLowerCase()) >= 0;
if (!currFilter.startsWith("!") && !found || currFilter.startsWith("!") && found) {
return true;
}
return false;
}
}
//if we have a query for the startnode, we will use that.
if ($scope.model.config.startNode.query) {
var rootId = $routeParams.id;
entityResource.getByQuery($scope.model.config.startNode.query, rootId, "Document").then(function (ent) {
dialogOptions.startNodeId = ent.id;
});
} else {
dialogOptions.startNodeId = $scope.model.config.startNode.id;
}
//dialog
$scope.openContentPicker = function () {
$scope.contentPickerOverlay = dialogOptions;
$scope.contentPickerOverlay.view = "treepicker";
$scope.contentPickerOverlay.show = true;
$scope.contentPickerOverlay.submit = function (model) {
if (angular.isArray(model.selection)) {
_.each(model.selection, function (item, i) {
$scope.add(item);
});
}
$scope.contentPickerOverlay.show = false;
$scope.contentPickerOverlay = null;
}
$scope.contentPickerOverlay.close = function (oldModel) {
$scope.contentPickerOverlay.show = false;
$scope.contentPickerOverlay = null;
}
};
$scope.remove = function (index) {
$scope.renderModel.splice(index, 1);
angularHelper.getCurrentForm($scope).$setDirty();
};
$scope.showNode = function (index) {
var item = $scope.renderModel[index];
var id = item.id;
var section = $scope.model.config.startNode.type.toLowerCase();
entityResource.getPath(id, entityType).then(function (path) {
navigationService.changeSection(section);
navigationService.showTree(section, {
tree: section, path: path, forceReload: false, activate: true
});
var routePath = section + "/" + section + "/edit/" + id.toString();
$location.path(routePath).search("");
});
}
$scope.add = function (item) {
var currIds = _.map($scope.renderModel, function (i) {
return i.id;
});
if (currIds.indexOf(item.id) < 0) {
item.icon = iconHelper.convertFromLegacyIcon(item.icon);
$scope.renderModel.push({ name: item.name, id: item.id, icon: item.icon, path: item.path, contentTypeAlias: item.metaData.ContentTypeAlias });
}
};
$scope.clear = function () {
$scope.renderModel = [];
};
var unsubscribe = $scope.$on("formSubmitting", function (ev, args) {
var currIds = _.map($scope.renderModel, function (i) {
return i.id;
});
$scope.model.value = trim(currIds.join(), ",");
});
//when the scope is destroyed we need to unsubscribe
$scope.$on('$destroy', function () {
unsubscribe();
});
//load current data
var modelIds = $scope.model.value ? $scope.model.value.split(',') : [];
entityResource.getByIds(modelIds, entityType).then(function (data) {
//Ensure we populate the render model in the same order that the ids were stored!
_.each(modelIds, function (id, i) {
var entity = _.find(data, function (d) {
return d.id == id;
});
if (entity) {
entity.icon = iconHelper.convertFromLegacyIcon(entity.icon);
$scope.renderModel.push({ name: entity.name, id: entity.id, icon: entity.icon, path: entity.path, contentTypeAlias: entity.metaData.ContentTypeAlias });
}
});
//everything is loaded, start the watch on the model
startWatch();
});
}
angular.module('umbraco').controller("Umbraco.PropertyEditors.CustomContentPickerController", customContentPickerController);
I would like to know which of these 2 patterns would be better:
/photos/123/edit
or
/photos/edit/123
Currently I am using the first, which gives me a Whoops, looks like something went wrong. when I try /photos/123/editxx instead of a 404 not found.
routes:
I am unsure where to look for the mistake, these are the photos routes:
Route::get('photos/randpics','PhotosController#randpics');
Route::get('photos/{id}/edit','PhotosController#getEdit')->middleware(['auth']);
Route::post('photos/{id}/edit','PhotosController#postEdit')->middleware(['auth']);
Route::post('photos/{id}/retag', ['as' => 'photos.retag', 'uses' => 'PhotosController#retag'])->middleware(['auth']);
Route::post('photos/{id}/delete','PhotosController#delete')->middleware(['auth']);
Route::get('photos/{id}/albums', 'PhotosController#getAlbums')->middleware(['auth']);
Route::post('photos/{id}/albums', 'PhotosController#postAlbums')->middleware(['auth']);
Route::get('photos/{id}/detail','PhotosController#detail');
Route::get('photos/{id}','PhotosController#single');
Route::post('photos/like', 'PhotosController#postLike')->middleware(['auth']);
Route::post('photos/unlike', 'PhotosController#postUnlike')->middleware(['auth']);
Route::get('photos','PhotosController#index');
getEdit() and postEdit():
The same error, complaining about an undefined variable in the master layout template appears, when I enter /photos/123/a/a/a/ for example.
public function getEdit(Request $request, $id = null)
{
$pic = Pic::findOrFail($id);
if(Gate::denies('edit-pic',$pic)) {
abort(403);
}
$pic->text = htmlspecialchars($pic->text);
$years = array_combine(range(date("Y"), 1960), range(date("Y"), 1960));
$location = $pic->location;
$tags = $pic->tags;
$tagsarray = $pic->tagNames();
$albums = $pic->albums;
$locations = array();
$getlocations = Location::orderBy('city')->get();
foreach($getlocations as $gl)
{
$locations[$gl->id] = $gl->city.' ('.$gl->country.')';
}
$cats = Cat::lists('cat','cat')->all();
return view('photos.edit',compact('pic','location','tags','tagsarray','albums','locations','cats','years'));
}
public function postEdit(Request $request, $id = null)
{
$pic = Pic::findOrFail($id);
if(Gate::denies('edit-pic',$pic)) {
abort(403);
}
$this->validate($request, [
'title' => 'max:200',
'text' => 'max:3000',
'location' => 'required|exists:locations,id',
'cat' => 'required|exists:cats,cat',
'jahrprod' => 'date_format:Y'
]);
$pic->title = trim($request->input('title'));
$pic->text = trim($request->input('text'));
$pic->jahrprod = ($request->input('jahrprod')) ? $request->input('jahrprod') : null;
$pic->location_id = $request->input('location');
$pic->cat = $request->input('cat');
$pic->save();
#mail
$maildata = array(
'msg' => 'picture '.$id.' ( '.$request->input('title').' ) was edited by '.Auth::user()->username
);
Mail::send(['text' => 'emails.empty'], $maildata, function($message){
$message->to('xx#yy.de')->from('xx#yy.de')->subject('picture edited');
});
return back()->with('success','photo information updated');
}
Controller.php
It seems, with more than 2 URL segments, the Controller.php is not working properly. /domain.xy/1/2 shows the 8 but /domain.xy/1/2/3 throws the error Undefined variable: photos_online
<?php
namespace App\Http\Controllers;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Auth;
use Cache;
use DB;
use App\Pic;
use App\Upload;
use Carbon\Carbon;
class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
public function __construct()
{
dd(8);
//.......
}
}
If you follow laravel's resource controller guidelines
https://laravel.com/docs/5.2/controllers#restful-resource-controllers
You should go with the first one.
But to fix your problem show us your route and controller function handling it.
Update
open AppServiceProvider located in app/http/providers
and replace boot() function with this
public function boot()
{
//initilizw $photos_online
$photos_online = Cache::rememberForever('index_countpics', function()
{
return Pic::count();
});
#pics today
if (Cache::has('pics_today')){
$pics_today = Cache::get('pics_today');
}else{
$pics_today = Pic::whereRaw('DATE(created_at) = DATE(NOW())')->count();
Cache::put('pics_today', $pics_today, Carbon::tomorrow());
}
# count waiting uploads
$waiting_uploads = Cache::rememberForever('waiting_uploads', function()
{
return Upload::where('accepted',0)->where('infos',1)->count();
});
# user online
$client_ip = request()->ip();
$check = DB::table('useronline')->where('ip', $client_ip)->first();
$username = (Auth::guest()) ? null : Auth::user()->username;
$displayname = (Auth::guest()) ? null : Auth::user()->displayname;
if(is_null($check)){
DB::table('useronline')->insert(['ip' => $client_ip, 'datum' => DB::raw('NOW()'), 'username' => $username, 'displayname' => $displayname]);
}else{
DB::table('useronline')->where('ip', $client_ip)->update(['datum' => DB::raw('NOW()'), 'username' => $username, 'displayname' => $displayname]);
}
DB::delete('DELETE FROM useronline WHERE DATE_SUB(NOW(), INTERVAL 3 MINUTE) > datum');
$users_online = DB::table('useronline')->whereNotNull('username')->get();
$guests_online = DB::table('useronline')->count();
#unread messages
$unread_messages = 0;
if(Auth::check()){
$unread_messages = Auth::user()->newThreadsCount();
}
view()->share('photos_online',$photos_online);
view()->share('pics_today',$pics_today);
view()->share('waiting_uploads',$waiting_uploads);
view()->share('users_online',$users_online);
view()->share('guests_online',$guests_online);
view()->share('unread_messages',$unread_messages);
}
Highlighting multiple words work fine without tags in source but I'm looking for a way to do it with tags.
For example if the search is "jo ramo" the results should be "Joey Ramones".
$(function() {
$("#autocomplete").autocomplete({
source: [
{ "label": "<span class=\"item1\">Joey</span> <span class=\"item2\">Ramones</span>"},
{ "label": "<span class=\"item1\">Johnny</span> <span class=\"item2\">Ramones</span>"},
{ "label": "<span class=\"item1\">Dee Dee</span> <span class=\"item2\">Ramones</span>"}
],
minLength: 2
})
.data("ui-autocomplete")._renderItem = function(ul, item) {
var searchMask = this.element.val();
var regEx = new RegExp(searchMask, "ig");
var replaceMask = "<b>$&</b>";
var html = item.label.replace(regEx, replaceMask);
return $("<li></li>")
.data("item.autocomplete", item)
.append($('<div class="item"></div>').html(html))
.appendTo(ul);
}
});
Here is a Fiddle
Thanks for your help.
As per previous post we can override the autocomplete filter methods to create our custom filters.
$.ui.autocomplete.filter = function (array, term) {
term=term.trim().replace(/\s+/g, '[^]*');// to search multiple words
var matcher = new RegExp("(" + term + ")", "i");
return $.grep(array, function (value) {
return matcher.test(value.label || value.value || value);
});
};
To match a "jo ramo" pattern to "Joey Ramones" i used [^]* in RegExp
Matched elements are pushed to _renderItem function, modified the function as per required ui(to highlight multiple words)
function(ul, item) {
var searchMask = this.element.val().trim();
var regEx = new RegExp(searchMask, "ig");
var replaceMask = "<b>$&</b>";
var html=$(item.label).text(); // manipulating text only
var splitText = searchMask.split(' ');
$.each( splitText, function( index, value ){
html = html.replace(new RegExp(value, "ig"), replaceMask);
});
return $("<li></li>")
.data("item.autocomplete", item)
.append($('<div class="item"></div>').html(html))
.appendTo(ul);
}
example : http://codepen.io/anon/pen/zrqQzw
I have written a code to integrate timepicker with editable which is being used to make all coulmns except the hidden id coulmn and the first shown coulmn editable . I couldn't get the fnupdate make my edited coulmn to be updated to the new value when it is posted to server side . I am able to get the posted values for server side processing but the clientside is not gettting updated by fnupdate .
Please see the code below and try to tell me what i am doing wrong because i am having many pages which function the same way .
$(document).ready(function() {
oTable = $('#scheduleTable').dataTable(
{
"sDom" : '<"top"flip>rt<"bottom"<"clear">',
"bAutoWidth" : false,
"bProcessing" : true,
bJQueryUI:true,
"bServerSide": true,
"bFilter":false,
"bSort": false,
"bInfo": false,
"bPaginate":false,
"aoColumns":[
{
"bVisible" : false
},
{
},
{},
{},
{},
{}
],
"fnRowCallback" : function (nRow, aData, iDisplayIndex) {
$(nRow).attr('id', '' + aData[0]);
//i starting from one to make the first element in td non editable
for (i = 1; i < aData.length; i ++) {
$('td:eq(' + i + ') ', nRow).editable("<?= $aupdateUrl; ?>", {
'callback': function (sValue, y) {
var aPos = oTable.fnGetPosition(this);
oTable.fnUpdate(sValue, aPos[0], aPos[1]);
},
"submitdata": function ( value, settings ) {
return {
"row_id": this.parentNode.getAttribute('id'),
"column": oTable.fnGetPosition( this )[2]
};
},
'height': '14px',
indicator : 'Saving...',
tooltip : 'Doubleclick to edit...',
type : "timepicker",
placeholder : ' '
});
}
return nRow;
},
"sAjaxSource" : "<?= $aSourceList; ?>/startdate/<?= $this->startdate; ?>"
}
);
});
$('.ui-datepicker-close').live('click', function (e){
e.preventDefault();
$('#scheduleTable tbody td input').parents("form").submit();
});
$.editable.addInputType('timepicker',{
/*create input element*/
element:function(settings,orginal){
var form = $(this),
input = $('<input type="text">');
form.append(input);
return (input);
},
plugin:function(settings,original){
/*Don't cancel inline editing onblur to allow clicking datepicker*/
settings.onblur = 'nothing';
$("input",this).filter(":text").timepicker(
{ timeFormat: 'hh:mm',
'hourMin':6,
'hourMax':21,
'showSecond': false,
'hourGrid':2,
'minuteGrid':10
}
);
}
});
I was able to solve the problem .The main thing that i was doing wrong was that i didn't have json response with only one value from my server side zend framework action.Therefore it caused the editable to function in a way that it couldn't put the value(the response) as the new value in the td element. Hope some on find it usefull peace!!