Seite 1 von 1

jQuery Upgrade im Backend && Double Jquery

Verfasst: Mi 26. Feb 2014, 10:31
von rethus
Contenido Version 4.9.2:

IST
jQuery 1.8.3
jQuery-UI 1.8.3
Aktuelle Version:
jQuery 2.1.0
jQuery-UI 1.10.4
Bei der Arbeit mit jQuery im Backend bin ich zudem auf folgendes Problem gestoßen.

jQuery ist recht empfindlich, was die Reihenfolge geladener Plugins etc. angeht. So kann man jQuery-UI nur dann erfolgreich laden, wenn zuvor jQuery geladen wurde.
Wenn man allerdings folgende Ladereihenfolge hat, kommt es zu seltsamen begleiterscheinungen:
jQuery → jQuery-UI → jQuery
Denn dann zum Beispiel wird ein einfaches Script zum öffenen eines UI-Dialogs wie dieses:

Code: Alles auswählen

<script>   
$(document).ready(function(){
   //Modal
   $('#cTpro_dialog_open').click(function() {
      $('#cTpro_dialog').dialog("open");
   });

    $( "#cTpro_dialog" ).dialog({
      autoOpen: false,
      show: {
        effect: "slide",
        duration: 1000
      },
      hide: {
        effect: "fold",
        duration: 1000
      },
      resizable: true,
      height:800,
      width:800,
      modal: true,
      buttons: {
        "Speichern": function() {
          $('#form_auswahl').submit();
        },
        "Abbrechen": function() {
          $('#form_empty').submit();
        }
      }
    });
 });
  
  </script>
mit einem Fehler wie dem folgenden Quittiert:
Uncaught TypeError: Object [object Object] has no method 'dialog'
Ursache:
Die Ursache, weshalb jquery doppelt eingebunden wird, liegt darin, dass ab 4.9 jquery für das Backend zur Verfügung steht und automatisch geladen wird.
Habe ich nun ein Layout, welches auch jQuery und jQuery-UI laden soll, werden die Scripte zweimal eingebunden. Einmal über das Backend-Framework, und einmal über die darzustellende Seite, die ja auch aus dem Layout generiert wird.

Anregung:
Nun kann man natürlich im Layout (unschönen) PHP-Code einfügen um jQuery nur dann zu laden, wenn die Seite NICHT im Backend geladen wird:

Code: Alles auswählen

<?php
if(!cRegistry::isBackendEditMode()) {
?>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<?php
}
?>
Klar das geht, bringt aber 2 ganz große Nachteile mit sich:
  • Das Layout muss mit PHP bestückt werden
  • Versionsunterschiede. Nutzt man im Backend das (mit ausgelieferte) antiquierte 1.8.3, und verwendet im Front-End 2.1.0, kommt man sich ggf. mit dem Funktionsumfang und vor allem Funktionen die "deprecated" sind in die Quere.
Daher zum einen die Bitte, jquery aktuell zu halten, oder noch besser:
  • Fügt einen Config-Zeiger hinzu, mit dem man ganz einfach weitere jQuery und jQuery-UI Packeges (als jeweils separates Unterverzeichnis) im System ablegen kann.
  • Dann kann jeder kurz die Konfig anpassen und einen Switch auf Version x.y.z ausprobieren
  • Zudem ein Config-Switch, ob jQuery und jQuery-UI auch im Frontend verwendet werden soll (dies dann bei aktivierung einfach mit ins Layout laden).
Auf diese Art kann man schnell mal jquery aktualisieren, und umgeht das Problem des doppelten Ladens der Dateien

Re: jQuery Upgrade im Backend && Double Jquery

Verfasst: Mi 26. Feb 2014, 10:52
von Oldperl
Hi,

also im Backend würde ich eher auf einen eigenen Namespace für das vom System eingesetzte jQuery und Systemscripte setzen. So kann der Entwickler selbst entscheiden ob er sein eigenes jQuery oder das des Systems einsetzt. Bei Plugins kann man zum Beispiel auch überlegen eine Schnittstelle anzubieten über die ich eigene JS-Scripte anmelden kann, die dann in einem eigene Namespace, z.B. mit dem Pluginnamen als Prefix laufen.

Im FE sollte sich der Entwickler selbst kümmern und nicht Contenido zuständig sein.

Gruß aus Franken

Ortwin

Re: jQuery Upgrade im Backend && Double Jquery

Verfasst: Mi 26. Feb 2014, 10:53
von rethus
Noch eine Ergänzung dazu.

Im Backend werden Meta-Tags und jQuery immer direkt vor dem schließenden <head>-Tag eingefügt.
Damit ist es auch unmöglich, z.B. ein jQuery Plugin welches im Front- und Backend geldaden werden soll, im Layout im <head> anzugeben, da jQuery im Backend immer wie oben beschrieben hinzugefügt werden, und somit die Plugins folgende Fehlermeldungen produzieren:

Code: Alles auswählen

Uncaught ReferenceError: jQuery is not defined 
Sieht dann ungefähr so aus im Source-Code:

Code: Alles auswählen

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link href="//code.jquery.com/ui/1.9.2/themes/cupertino/jquery-ui.css" rel="stylesheet" type="text/css" >
<link href="css/style_d1.css?a=094630" rel="stylesheet" type="text/css" />
<link href="/cms/prettyPhoto/css/prettyPhoto.css" rel="stylesheet" type="text/css" />
<script src="/cms/prettyPhoto/js/jquery.prettyPhoto.js"></script>
<title>als Arbeitgeber</title>
<link rel="stylesheet" type="text/css" href="//dev.domain.tld/cms/cache/d1_standard.css" id="m1736" />

<meta name="description" content="Karriere Seite der Gruppe" />
<meta name="robots" content="index, follow" />
<meta name="generator" content="CMS CONTENIDO 4.9" />
<meta http-equiv="Content-Type" name="" />
<meta name="author" content="Silke" />
<meta name="date" content="2014-02-25 15:43:11" />
<meta name="keywords" content="mitarbeiter" />

    <script type="text/javascript">
    // @todo  Use conMarkSubmenuItem(id) in general.js, but we have to ensure to load the file!
    (function(id) {
        var menuItem;

        try {
            // Check if we are in a dual-frame or a quad-frame
            if (parent.parent.frames[0].name == "header") {
                if (parent.frames["right_top"].document.getElementById(id)) {
                    menuItem = parent.frames["right_top"].document.getElementById(id).getElementsByTagName("a")[0];
                    parent.frames["right_top"].sub.clicked(menuItem);
                }
            } else {
                // Check if submenuItem is existing and mark it
                if (parent.parent.frames["right"].frames["right_top"].document.getElementById(id)) {
                    menuItem = parent.parent.frames["right"].frames["right_top"].document.getElementById(id).getElementsByTagName("a")[0];
                    parent.parent.frames["right"].frames["right_top"].sub.clicked(menuItem);
                }
            }
        } catch (e) {}
    })("c_4");
    </script> <style type="text/css">
    .defaultSkin table.mceLayout {position: absolute; z-index: 10000;}
    .defaultSkin #mce_fullscreen_tbl {z-index: 20000;}
    .defaultSkin .mcePlaceHolder {position: absolute; z-index: 10000;}
</style>

<script src="http://dev.domain.tld/contenido/scripts/jquery/jquery.js" type="text/javascript"></script>
<script src="http://dev.domain.tld/contenido/scripts/general.js" type="text/javascript"></script>
<script src="http://dev.domain.tld/contenido/scripts/con_tiny.js" type="text/javascript"></script>
<!-- tinyMCE -->
<script src="http://dev.domain.tld/contenido/external/wysiwyg/tinymce3/jscripts/tiny_mce/tiny_mce.js" type="text/javascript"></script>

<script type="text/javascript">
    tinymce.create('tinymce.plugins.ClosePlugin', {
        init: function(ed, url) {

            ed.addButton('save', {
                title   : 'Editor schließen und Änderungen speichern',
                image   : 'http://dev.domain.tld/contenido/images/but_save_tiny.gif',
                icons   : false,
                onclick : function(ed) {

                    setcontent(iIdartlang, '0');

                }
            });

            ed.addButton('close', {
                title   : 'Editor schließen',
                image   : 'http://dev.domain.tld/contenido/images/but_close_tiny.gif',
                icons   : false,
                onclick : function(ed) {

                    closeTiny();

                }
            });

        }
    });

    // Register plugin with a short name
    tinymce.PluginManager.add('close', tinymce.plugins.ClosePlugin);

    var active_id = null;  //id of div on which tiny is active
    var active_object = null;  //onject of div on which tiny is active
    var aEditdata = new Object();  //global array which stores edited content
    var aEditdataOrig = new Object();  //global array which stored original content (Importent for decision if content has changed)
    var bCheckLeave = true;  //globak var which defines if user is asked to store changes

    //Global vars for CONTENIDO popup filebrowser
    var fb_fieldname;
    var fb_handle;
    var fb_intervalhandle;
    var fb_win;

    //Configuration of tiny, when tiny is opened set event which stores original
    //content to global var aEditdataOrig
    var tinymceConfigs = {
        document_base_url: "http://dev.domain.tld/cms/",
    'article_url_suffix': 'front_content.php?idart=111',
	'mode': 'exact',
	'content_css': 'http://dev.domain.tld/cms/css/style_tiny.css',
	'theme': 'advanced',
	'theme_advanced_path_location': 'bottom',
	'remove_script_host': false,
	'file_browser_callback': 'myCustomFileBrowser',
	'theme_advanced_resizing': true,
	'pagebreak_separator': '<!-- my page break -->',
	'apply_source_formatting': true,
	'remove_linebreaks': false,
	'convert_urls': false,
	'relative_urls': false,
	'elements': '*',
	'language': 'de',
	'cleanup_callback': '',
	'height': '210px',
	'directionality': 'ltr',
	'theme_advanced_toolbar_align': 'left',
	'plugin_insertdate_dateFormat': '%d.%m.%Y',
	'plugin_insertdate_timeFormat': '%H:%M:%S',
	'theme_advanced_buttons1': 'bold,italic,underline,strikethrough,separator,undo,separator,bullist,numlist,separator,forecolor,backcolor,separator,justifyleft,justifycenter,justifyright,separator,fullscreen,separator,save,close',
	'theme_advanced_buttons2': '',
	'theme_advanced_buttons3': '',
	'plugins': 'table,inlinepopups,fullscreen,close',
	'valid_elements': '*[*]',
	'extended_valid_elements': 'form[name|action|method],textarea[name|style|cols|rows],input[type|name|value|style|onclick],a[name|href|target|title|onclick],img[class|src|border=0|alt|title|hspace|vspace|width|height|align|onmouseover|onmouseout|name],hr[class|width|size|noshade],font[face|size|color|style],span[class|align|style]',
	'contenido_background_color': 'white',
	'setupcontent_callback': 'myCustomSetupContent',
	'auto_resize': false,
	'theme_advanced_resizing_use_cookie': false,
	'theme_advanced_toolbar_location': 'external',
        fullscreen_settings: {
            'theme_advanced_buttons1': 'cut,copy,paste,pastetext,pasteword,|,search,replace,|,undo,redo,|,bold,italic,underline,strikethrough,sub,sup,|,insertdate,inserttime,preview,|,styleselect,|,visualchars,nonbreaking,template,pagebreak,|,help,|,fullscreen',
'theme_advanced_buttons2': 'link,unlink,anchor,image,media,advhr,|,bullist,numlist,|,outdent,indent,blockquote,|,justifyleft,justifycenter,justifyright,justifyfull,removeformat,|,forecolor,backcolor,|,ltr,rtl,|,visualaid,charmap,cleanup,|,code',
'theme_advanced_buttons3': 'tablecontrols,|,formatselect,fontselect,fontsizeselect,|,styleprops,|,cite,abbr,acronym,del,ins,attribs',
'theme_advanced_toolbar_align': 'left',
'plugins': 'safari,table,save,advhr,advimage,advlink,pagebreak,style,layer,insertdatetime,preview,media,searchreplace,print,contextmenu,paste,directionality,fullscreen,visualchars,nonbreaking,xhtmlxtras,template,inlinepopups'

        },
        'setup': function(ed) {
            ed.onSetContent.add(function(ed, o) {
                updateContent(ed.getContent());
            });
        }
    };
    tinyMCE.settings = tinymceConfigs;

    //add tiny to elements which contains classname contentEditable
    //tiny toggles on click
    $(document).ready(function() {
        $('div[contenteditable=true]').each(function() {
            $(this).attr('contentEditable', 'false'); //remove coneditable tags in order to disable special firefox behaviour
            $(this).bind("click", function() {
                
            });
        });
    });

    //activate save confirmation on page leave
    $(window).unload(function() {
        leave_check();
    });

    var file_url = "http://dev.domain.tld/contenido/frameset.php?area=upl&contenido=jp17069b0oeah6a094234983b551hima&appendparameters=filebrowser"; //Global var which contains url to CONTENIDO image browser
    var image_url = "http://dev.domain.tld/contenido/frameset.php?area=upl&contenido=jp17069b0oeah6a094234983b551hima&appendparameters=imagebrowser"; //Global var which contains url to CONTENIDO file browser
    var flash_url = "http://dev.domain.tld/contenido/frameset.php?area=upl&contenido=jp17069b0oeah6a094234983b551hima&appendparameters=imagebrowser"; //Global var which contains url to CONTENIDO flash browser
    var media_url = "http://dev.domain.tld/contenido/frameset.php?area=upl&contenido=jp17069b0oeah6a094234983b551hima&appendparameters=imagebrowser"; //Global var which contains url to CONTENIDO media browser
    var frontend_path = "http://dev.domain.tld/cms/";

    var iIdartlang = '157'; //Idartlang which is currently edited
    var sQuestion = 'M&ouml;chten Sie die &Auml;nderungen speichern?'; //Translation of save confirmation

</script>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head>

Re: jQuery Upgrade im Backend && Double Jquery

Verfasst: Mi 26. Feb 2014, 10:55
von Faar
Man kann auch ein kleines Modul im Layout Container einbinden, das je nach Editmode oder nicht, jQuery einbindet. :wink:

Die Scripte zum ansteuern dann in den Footer.

Re: jQuery Upgrade im Backend && Double Jquery

Verfasst: Do 27. Feb 2014, 12:15
von rethus
Man kann da ne ganze Menge machen, doch es geht mir hier darum, Contenido im CORE zu verbessern. Das arbeiten und entwickeln soll ja leichter werden, damit möglichst viele Entwickler sich für Contenido entscheiden und die (Entwicklungs)Kosten für Kunden die das System einsetzen gering bleibt.

Re: jQuery Upgrade im Backend && Double Jquery

Verfasst: Mo 4. Aug 2014, 15:23
von rethus
Gibt es hier schon FeedBack von den CoreEntwicklern. Würde mich interessieren, welcher Ansatz hier künftig verfolgt wird.