Giter Site home page Giter Site logo

vojtech-dobes / nette.ajax.js Goto Github PK

View Code? Open in Web Editor NEW
149.0 149.0 84.0 136 KB

Flexible AJAX for Nette Framework. Supports snippets, redirects etc.

Home Page: https://componette.org/vojtech-dobes/nette.ajax.js/

License: MIT License

JavaScript 100.00%
ajax ajaxification javascript jquery nette nette-framework

nette.ajax.js's People

Contributors

ciki avatar david-sabata avatar dg avatar enumag avatar fprochazka avatar iguana007 avatar janmarek avatar jiripudil avatar leonardoca avatar lm avatar matopeto avatar ondrs avatar pepakriz avatar pinguspepan avatar raxtor avatar rostenkowski avatar solcik avatar stefi023 avatar stekycz avatar trejjam avatar uestla avatar venca-x avatar voda avatar vojtech-dobes avatar xificurk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

nette.ajax.js's Issues

Problem with input.ajax in form.ajax

I need put input.ajax into my .ajax form, but due to this code:

$(this.buttonSelector).each(function () {
            $(this).closest('form').off('click.nette', this.buttonSelector, rh)
                .on('click.nette', this.buttonSelector, rh);
        });

it causes, that all the form is clickable and sends ajax requests.

Consider automatic inicialization

There is an event, that get's called after everything is loaded and executed. I use it without problems to init $.nette ajax.

jQuery(window).load(function () {
    jQuery.nette.init();
});

Please consider doing it automatically

Complete event does not fire if ajax request fails

Complete event gets fired only for successful requests. For failed requests e.g. due syntax error on server only error is triggerred
simple test case:

$.nette.ext({
        complete: function() { console.log('complete'); },
        error: function() { console.log('error'); },
        success: function() { console.log('success'); }
    });

Popstate on page's load in WebKit based browsers

"The problem is well-known — Chrome and Firefox treat that popstate event differently. While Firefox doesn't fire it up on the first load, Chrome does." (see http://stackoverflow.com/questions/6421769/popstate-on-pages-load-in-chrome for example). Although the problem is well-know, it's not handled properly in history.ajax.js (or at least it seems to me). In my case, this results in an extra Ajax call when using history.ajax.js. When I load a page in Chrome, it gets immediately refreshed using Ajax.

I'm not familiar with History API or history.ajax.js so I'm not able to suggest a solid working solution. As a workaround, I added a simple counter of events for webkit based browsers and using this counter, I'm able to ignore the first event.

Consider data attribute `data-ajax-on` and sleeping extensions

If I create some component-level extension I don't want to add data-ajax-off="..." to every .ajax element on the page.

Alternatively I could validate the firing element to be the desired one in the extension code, but such element marking could be more straightforward.

It would be nice to be able to add a "sleeping" extension - disabled by default - and enabled only for marked elements.
What do you thing?

Remove snippet

Mám usecase: "Smazání řádku, souboru ..."

Tak nechci snippet překreslovat něčím co bude prázdné ale rovnou ho smazat už ho nepotřebuji.

updateSnippet: function ($el, html, back) {
        if(html === 'remove') {
            return $el.remove();
        }

Když mám například snippet jako tag li tak tímto se mi smaže a nezůstane prázdná tečka v seznamu.

Custom callbacks on a.ajax won't fire

I can't figure out how to make my custom callbacks work.

Anything like $('body').on('click', 'a.ajax', function(){ … }); gets prevented from firing once I call $.nette.init();

Inside the function I need to work with $(this) (the element clicked). Thanks for your advice...

Event is always cancelled

$('[type=checkbox]').click(function (e) {
    $(this).netteAjax(e);
});

Event will get killed and checkbox won't change its status. There probably should be way how to allow the event to continue.

Idea: Create queue of callbacks

When you create an extension, you might wanna do something, before the "native" extensions get called. The problem with javascript is, that it does sort object properties randomly. If you'd create a array queue from each event, the callbacks would sort in the way they were added. When they sort, you can than reverse the order, to make the later added callback get invoked first. (Nette does this with it's macros)

So the result would be, I'd add my extension, that would manipulate snippets and handle proper discard of objects and events attached to elements, before they get replaced. And could, after the snippet gets replaced, in complete event create the new objects.

Add composer support

Now when the project contains PHP classes it is good time to add Composer (and it's autoload feature) support.

multiple form submission failure

I am trying to manually submit form using nette.ajax but it only gets submitted first time. Other times it ends on this condition because statusText is set to cancelled - magic for me. I don't really have any idea what's wrong or where I should start digging. Any help will be appreciated!

Code I use:

fileUploadForm.on('submit.file-upload', function(e) {
                                    $(this).netteAjax(e, {
                                        complete: function(payload, status, xhr) {
                                            basicFileUploadHandler._successCb(payload, status, xhr, uploadRow, filesize);
                                        }
                                    });
                                    fileUploadForm.off('submit.file-upload');
                                    e.stopImmediatePropagation();
                                    e.preventDefault();
                                    return false;
                                }).trigger('submit.file-upload');

Feature: create callback for resetting javascript events on snippet html

When HTML is loaded by jQuery, callbacks that programmers attached to some elements on page load are not automatically attached to the new html, which is often a problem. I'd welcome a feature that allows me to easily re-initialize javascript on HTML in snippets, I solved it by adding this code into snippets.applySnippet method:

if ($.nette.ext('reset-snippet-js')) {
    html = $(html);
    $.nette.ext('reset-snippet-js').resetSnippet(html);
}

Then I call this on document load:

$.nette.ext('reset-snippet-js', {}, {
    resetSnippet: function($snippet) {
        initToggleBox($snippet.find('.c-box')); //some my function to add some behavior
    }
    });

You can integrate these simple lines if you agree with me or maybe even more robust solution with some event raised for each refreshed snippet...

thanks

AJAX history - pushState / hashbang

Example of using with old ajax jquery script

Hashbang based on http://benalman.com/projects/jquery-bbq-plugin/
There is caching bug in IE - it's the reason of using date time variable in the request

ajax.js

$(document).ready(function() {

// AJAX submit with .ajaxhash - saving the history
var domain = 'http://' + document.location.host;
var url = '';
var counter = 0;
var link = '';

$("a.ajaxhash").live("click", function (event) {
    // HTML5 pushState compatible browsers
    if (history.pushState) {
        // if we call replaceState on load there will be first url two times in history - but we need the rest of this function
        if (counter == 0) {
            window.history.replaceState({
                href: window.location.toString()
            }, "", window.location);
            counter = counter + 1;
        }

        window.history.pushState({
            href: this.href
        }, "", this.href);
        event.preventDefault();
        $.get(this.href);
    } else {
        url = this.href.substring(domain.length, this.href.length);
        $.bbq.pushState('#!' + url);
        event.preventDefault();
    }

    // showing the spinner and settings his position
    $("#ajax-spinner").show().css({
        position: "absolute",
        left: event.pageX - 24,
        top: event.pageY + 10
    }).ajaxStop(function() {
        $(this).hide();

    });

});

// on document load
// pustState HTML5
if (history.pushState) {

    $(window).bind('popstate', function(event) {
        $.post(event.originalEvent.state.href, $.nette.success);
    });

// hashbang HTML4        
} else {
    $(window).trigger("hashchange");
}    


// load AJAX content depending on hashbang
$(window).bind("hashchange", function(e) {

    url = '';

    for(key in $.bbq.getState()) {


        if ($.bbq.getState()[key] == '') {
            url = key.substring(1, key.length);
        } else if (url == '') {
            url = key.substring(1, key.length) + '=' + $.bbq.getState()[key];
        } else {
            url = url + '&' + key.substring(0, key.length) + '=' + $.bbq.getState()[key];
        }
    }

    if (url == undefined) {

        link = location.href;

        if ((link.split('?').length - 1) > 0) {
            link = location.href + '&cache=' + new Date().getTime();
        } else {
            link = location.href + '?cache=' + new Date().getTime();
        }

    } else if (url == '') {

        link = document.location.toString();
        if ((link.split('?').length - 1) > 0) {
            link = document.location + '&cache=' + new Date().getTime();
        } else {
            link = document.location + '?cache=' + new Date().getTime();
        }

    } else {

        link = url;
        if ((link.split('?').length - 1) > 0) {
            link = domain + url + '&cache=' + new Date().getTime();
        } else {
            link = domain + url + '?cache=' + new Date().getTime();
        }

    }
    $.get(link);
});

});

Problem installing venne/nette.ajax.js using composer

I have this is my composer in my require section:

"venne/nette-ajax": "dev-master",

Time to time it happens that composer outputs something like this on update or even install:

  - Updating venne/nette-ajax dev-master (3017278 => 05e46ff)
    Checking out 05e46ff7523c6f0397d6ee61169d5552e5e23316
    05e46ff7523c6f0397d6ee61169d5552e5e23316 is gone (history was rewritten?), recovered by checking out 30172784e595c65ea9f06653c62d2c7487b61367

And .js files keep jumping between root and client-side directories so that application doesn't work.

Problém po refresh: $el.get(0).tagName == 'TITLE'

Zjistil jsem jednu chybu na řádku 384:

Pokud nechávám při ajaxových requestech přepisovat URL a pak dám refresh stránky a použiji ajaxov request znovu, vypíše se mi chyba "$el.get(0) is undefined".

Pokud přidám do podmínky navíc $el.get(0)!==undefined tak je vše (zdá se) v pořádku.
Ale neznám celý skript tak důkladně, takže nevím zda je to skutečné řešení problému nebo jen berlička...

Poslední verze hlásí js error

Stáhl jsem si současnou verzi a konzoli mi to hází chybu:

TypeError: function (a) {var b = "[data-dismiss="alert"]", c = function (c) {a(c).on("click", b, this.close);};c.prototype.close = function (b) {
function f() {e.trigger("closed").remove();}

var c = a(this), d = c.attr("data-target"), e;d || (d = c.attr("href"), d = d && d.replace(/.(?=#[^\s]$)/, "")), e = a(d), b && b.preventDefault(), e.length || (e = c.hasClass("alert") ? c : c.parent()), e.trigger(b = a.Event("close"));if (b.isDefaultPrevented()) {return;}e.removeClass("in"), a.support.transition && e.hasClass("fade") ? e.on(a.support.transition.end, f) : f();}, a.fn.alert = function (b) {return this.each(function () {var d = a(this), e = d.data("alert");e || d.data("alert", e = new c(this)), typeof b == "string" && e[b].call(d);});}, a.fn.alert.Constructor = c, a(function () {a("body").on("click.alert.data-api", b, c.prototype.close);});}(window.jQuery) is not a function

Není to bug?

bootstrap datepicker & paginator & nette.ajax history.ajax.js

Hi, when i use bootstrap datepicker and paginator and history.ajax.js i have problem with NS_ERROR_ILLEGAL_VALUE: Component returned failure code: 0x80070057 (NS_ERROR_ILLEGAL_VALUE) [nsIDOMHistory.pushState].

Is nessecerary to use in row 86 on success metohod ui: findSnippets()? When i comment work it perfect.

success: function (payload) {
    var redirect = payload.redirect || payload.url; // backwards compatibility for 'url'
    if (redirect) {
        var regexp = new RegExp('//' + window.location.host + '($|/)');
        if ((redirect.substring(0,4) === 'http') ? regexp.test(redirect) : true) {
            this.href = redirect;
        } else {
            window.location.href = redirect;
        }
    }

    if (this.href && this.href != window.location.href) {
        history.pushState({
            nette: true,
            href: this.href,
            title: document.title,
            ui: findSnippets()
        }, document.title, this.href);
    }
    this.href = null;
}

Informace o verzi

Je to drobnost, ale hodilo by se mít někde (například i v úvodním komentáři) informaci o verzi.

Skript úspěšně provozuju v několika větvích, někde testím, někde zkouším nové fíčury a podobně, a ztrácím přehled o tom, kde mám kterou verzi, resp. který commit.

Hash commitu by byl možná ještě lepší, ale obyčejná číselná verze by bohatě stačila :-)

Allow triggering events externally

I have a library where I can't use $.nette.ajax directly, but I would still like to trigger events for updating snippets etc. Currently it is not possible at all. The only dirty solution is to patch nette.ajax.js itself, e.g. by adding:

    this.fakeSuccess = function (payload, status, xhr, off) {
        inner.fire({
            name: 'success',
            off: off || {}
        }, payload, status, xhr);
    };

State from previous request breaks other requests

Let's have a presenter

class HomepagePresenter extends BasePresenter
{
    /** @persistent */
    public $locale = 'cs';

}

When you send ajax to

/homepage?locale=en

the value for locale will be en and the returne state from Nette contains

{"state":{"locale":"en","backlink":null}}

Which is fine, but the next request looks like this

/homepage/?locale=en&locale=en&backlink=

Which is obviousely not right. But that would be the better part, because this still work. What is not fine, that when you send a request on

/homepage

the value for locale will be cs and Nette will return

{"state":{"locale":null,"backlink":null}}

And the next request will look like this

/homepage/?locale=&backlink=

And now the application is broken.

Use TrueHTML to avoid mXSS

TL;DR not even assumed sanitized HTML and CSS can be trusted in el.innerHTML or $(el).html(). Increase security by using JavaScript sanitizer like Google Caja.

More info:
http://www.nds.rub.de/research/publications/mXSS-Attacks/
http://www.slideshare.net/x00mario/the-innerhtml-apocalypse

Original issue nette/nette#1496


I would suggest delegating $(el).html(snippet) to separate method and by default using secure implementation via TrueHTML or at least sanitizing the input.
I haven't done enough research on this topic and futher research is necessary. Known affected are old versions of IE (8, 9), Firefox, Chrome. IE 11 XSS filter shows warning even for false positives which might break trust between user and site.

Form forced to GET and data not appended

I'll try to make further exploration later, because I am not sure if it is bad use, bug or even a feature ;)

Update:

Version: ALL

<form class="ajax" method="post"> is forced to be be sent via GET method

Query string parameter with the same name as the form field is not overwritten, so it is impossible to send form[q] if q is already present in URL.

Post data are not serialized within the POST request.

Add "cache:false" option to standard Ajax calls

I have been experiencing wird behaviour lately. While I'm used to close firefox browser with several tabs open, sometimes I have noticed the backed of application I'm working on has rendered json to browser instead of redirecting to login page. I was trying to fix the problem on php side, but there was nothing wrong. It took me quite a while to figure out where the problem is and when exactly is happennig.

The main reason is the ajax calls are cached by default. In my case after reopening tabs browser did not even try to make single request to server and displayed last json response instead.

After quick reasearch I have found out it's quite common issue and there are other related. Of course ii could be handled on server side by sending correct headers, but adding "cache:false" option to ajax request seems to me by far more efficient. see http://stackoverflow.com/questions/168963/stop-jquery-load-response-from-being-cached/168977#168977

Oznaceni verze v nette.ajax.js

Navrhuji do nette.ajax.js umistovat verzi aby bylo videt jakou mam aktualne verzi nasazenou a jakou verzi si mohu stahnout

WebKit initial request fix obstructs returning back to initial page

After testing history extension for nette.ajax.js I've encountered an unwanted feature in fix discussed here: #73.
When I click through some sections the plugin works just fine but when I navigate back through those sections I'm not able to load the initial page.
This part of 'popstate' handler is suspicious:

var initialPop = (popped && initialUrl == state.href);
// console.log('popped: ' + popped + '\ninitialUrl: ' + initialUrl + '\nstate.href: ' + state.href);
popped = true;
if (initialPop) {
    return;
}

https://github.com/vojtech-dobes/nette.ajax.js/blob/master/history/history.ajax.js#L45

Explained:

  • Initial loading and dump of variables
    vstiek
  • Navigating through some sections
    vstiek2
  • 1st step back (load successful)
    vstiek3
  • 2nd step back (load prevented by mentioned fix because initialUrl == state.href)
    vstiek4

My solution would be to add another variable containing true/false indication whether user has already loaded another page or not.

Error while submit form by Enter key

JS error: "TypeError: name is undefined"
Line 375: if (name.indexOf('[', 0) !== -1) { // inside a container

Clicking on submit button works fine.

History replace state, odstranění nevzhledných url.

Navrhuji, že by mohl být přidán history.repaceState pro zlikvidování nehezkých url vytvářených v nette. Čili _fid, do a další by mohli být odstraněny, u replace state není třeba řešit tlačítko zpět v prohlížeči jako u pushState, takže by to mohlo být ok, co myslíte?

Multiplier

Zdravim. Stáhl jsem poslední verzi ale nefunguje mi v Multiplier.
Formulář se vůbec neodešle. Na chvilku problikne spinner ale nic se neděje.
Když odeberu formuláři $form->getElementPrototype()->class(‚ajax‘);, tak vše funguje.
Dělám něco špatně?

HomepagePresenter.php

use Nette\Application\UI\Form;
use Nette\Application\UI\Multiplier;

class HomepagePresenter extends BasePresenter
{

    public function renderDefault()
    {
    }

  protected function createComponentShopForm()
  {
      $neco = $this;
      return new Multiplier(function ( $id ) use ( $neco ) {
          $form = new Nette\Application\UI\Form;
          $form->getElementPrototype()->class('ajax');
          $form->addText('count', 'Počet zboží:')
              ->addRule($form::FILLED)
              ->addRule($form::INTEGER);
          $form->addHidden('id', $id);
          $form->onSuccess[] = $neco->shopFormSubmitted;
          $form->addSubmit('create', 'Přidat do košiku');

          $form->setDefaults( array( 'count' => 1 ) );

          return $form;
      });
  }

  public function shopFormSubmitted(Form $form)
  {
      sleep(10);

      $aValues = $form->getValues(TRUE); // same as: (array) $form->values;

      $this->flashMessage("Přidáno do košíku id: ".$aValues["id"]." Kusu:".$aValues["count"], 'success');

      if (!$this->presenter->isAjax()) {
        $this->redirect('this');
      } else {
        $this->invalidateControl("flashMessage");
      }
  }

}

@layout.latte

  <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.min.js"></script>
  <script type="text/javascript" src="{$basePath}/js/netteForms.js"></script>
  <script type="text/javascript" src="{$basePath}/js/nette.ajax.js"></script>
  <script type="text/javascript" src="{$basePath}/js/extensions/spinner.ajax.js"></script>
  <script type="text/javascript" src="{$basePath}/js/ajax.js"></script>

  {snippet flashMessage}
       <div n:foreach="$flashes as $flash" class="flash {$flash->type}">{$flash->message}</div>
  {/snippet}

default.latte:

{block content}

{snippet matches}
  {for $i=0; $i<10; $i++}
      {snippet match-$i}
          {$i}
          {control shopForm-$i}
      {/snippet}
  {/for}
{/snippet}
{/block}

Na obyčejný formulář bez Multiplier vše funguje.

diagnostics.dumps problem in case of more request and slow nette debug bar initialization

Today I have noticed quite complex problem. As I tried to implement state save/load for Datatables and display some debug messages using barDump. They did not display. The reason is

  • Datatables.js sends another request before DebugBar finishes initialization.
  • diagnostics.dump.js are trying to locate barDump panel, do not find it and remember empty value and that's why debuging does not work even for all next ajax requests
  • as a quick fix I do not save panel element to this.panel variable

I have not figured out optimal solution yet. This case can be solved when DebugBar supports ajax itself, but I think this is a topic to keep in mind generally for any ajax communication. There can be some situations, when requests are running paralel and this might cause unexpected behaviour.

Make data-ajax-off less pain to write :)

Hi,

data-ajax-off is a cool feature, but it's kinda pain to write when you want to disable more than one extension. In that case, it has to be a valid JSON, otherwise it fails to parse and returns just string. So the definition looks like:

<a href="..." class="ajax" data-ajax-off='["snippets", "history", "ga"]'>...</a>

It'd be cool if it was possible to define it just like:

<a href="..." class="ajax" data-ajax-off="snippets, history, ga">...</a>

history.ajax.js - google chrome bug

ahoj, v google chrome nefunguje history.ajax.js společně s javascriptovou validací. (live-form-validation ani netteForms) Nevyhazuje to v konzoli žádnou chybu (event vůbec nereaguje)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.