Overview
Comment:Move site config to web section
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | dev
Files: files | file ages | folders
SHA1: 83475cf1ee74899ce5842a4a191de6d6c390f15d
User & Date: bohwaz on 2021-01-08 00:19:12
Other Links: branch diff | manifest | tags
Context
2021-01-08
00:27
Don't show site preview links when site is disabled check-in: 65104a27ac user: bohwaz tags: dev
00:19
Move site config to web section check-in: 83475cf1ee user: bohwaz tags: dev
00:01
Merge trunk back with dev check-in: 36efd105ad user: bohwaz tags: dev
Changes

Modified src/include/lib/Garradin/Config.php from [977640546b] to [09ca35fa0d].

69
70
71
72
73
74
75


76
77
78
79
80
81
82

		'couleur1'              => '?string',
		'couleur2'              => '?string',
		'image_fond'            => '?Garradin\Entities\Files\File',

		'desactiver_site'       => 'bool',
	];



	static protected $_instance = null;

	static public function getInstance()
	{
		return self::$_instance ?: self::$_instance = new self;
	}







>
>







69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84

		'couleur1'              => '?string',
		'couleur2'              => '?string',
		'image_fond'            => '?Garradin\Entities\Files\File',

		'desactiver_site'       => 'bool',
	];

	protected $_modified;

	static protected $_instance = null;

	static public function getInstance()
	{
		return self::$_instance ?: self::$_instance = new self;
	}
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
			$values[$key] = $value;
		}

		unset($value, $key, $modified);

		$db->begin();

		foreach ($this->modified as $key=>$modified)
		{
			$value = $this->config[$key];

			if (is_array($value))
			{
				$value = implode(',', $value);
			}
			elseif (is_object($value))
			{
				$value = (string) $value;
			}

			$db->preparedQuery('INSERT OR REPLACE INTO config (cle, valeur) VALUES (?, ?);',
				[$key, $value]);
		}

		if (!empty($this->modified['champ_identifiant']))
		{
			// Mettre les champs identifiant vides à NULL pour pouvoir créer un index unique
			$db->exec('UPDATE membres SET '.$this->get('champ_identifiant').' = NULL
				WHERE '.$this->get('champ_identifiant').' = "";');

			// Création de l'index unique
			$db->exec('DROP INDEX IF EXISTS membres_identifiant;');







|

|














|







148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
			$values[$key] = $value;
		}

		unset($value, $key, $modified);

		$db->begin();

		foreach ($this->_modified as $key=>$modified)
		{
			$value = $this->get($key);

			if (is_array($value))
			{
				$value = implode(',', $value);
			}
			elseif (is_object($value))
			{
				$value = (string) $value;
			}

			$db->preparedQuery('INSERT OR REPLACE INTO config (cle, valeur) VALUES (?, ?);',
				[$key, $value]);
		}

		if (!empty($this->_modified['champ_identifiant']))
		{
			// Mettre les champs identifiant vides à NULL pour pouvoir créer un index unique
			$db->exec('UPDATE membres SET '.$this->get('champ_identifiant').' = NULL
				WHERE '.$this->get('champ_identifiant').' = "";');

			// Création de l'index unique
			$db->exec('DROP INDEX IF EXISTS membres_identifiant;');

Modified src/templates/admin/_head.tpl from [a52e4cbdcf] to [ec48b7346f].

92
93
94
95
96
97
98

99
100
101

102
103
104
105
106
107
108
            <ul>
                <li class="{if $current == 'docs/recent'} current{/if}"><a href="{$admin_url}docs/recent.php">Récents</a></li>
            </ul>
            </li>
        {/if}
        {if $session->canAccess('web', Membres::DROIT_ACCES)}
            <li class="{if $current == 'web'} current{elseif $current_parent == 'web'} current_parent{/if}"><a href="{$admin_url}web/"><b class="icn">🖻</b><i> Site web</i></a>

            <ul>
                <li class="{if $current == 'web/themes'} current{/if}"><a href="{$admin_url}web/themes/">Thèmes</a></li>
            </ul>

            </li>
        {/if}
        {if $session->canAccess('config', Membres::DROIT_ADMIN)}
            <li class="main config{if $current == 'config'} current{elseif $current_parent == 'config'} current_parent{/if}"><a href="{$admin_url}config/"><b class="icn">☸</b><i> Configuration</i></a>
        {/if}
        <li class="{if $current == 'mes_infos'} current{elseif $current_parent == 'mes_infos'} current_parent{/if}">
            <a href="{$admin_url}mes_infos.php"><b class="icn">👤</b><i> Mes infos personnelles</i></a>







>



>







92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
            <ul>
                <li class="{if $current == 'docs/recent'} current{/if}"><a href="{$admin_url}docs/recent.php">Récents</a></li>
            </ul>
            </li>
        {/if}
        {if $session->canAccess('web', Membres::DROIT_ACCES)}
            <li class="{if $current == 'web'} current{elseif $current_parent == 'web'} current_parent{/if}"><a href="{$admin_url}web/"><b class="icn">🖻</b><i> Site web</i></a>
            {* TODO
            <ul>
                <li class="{if $current == 'web/themes'} current{/if}"><a href="{$admin_url}web/themes/">Thèmes</a></li>
            </ul>
            *}
            </li>
        {/if}
        {if $session->canAccess('config', Membres::DROIT_ADMIN)}
            <li class="main config{if $current == 'config'} current{elseif $current_parent == 'config'} current_parent{/if}"><a href="{$admin_url}config/"><b class="icn">☸</b><i> Configuration</i></a>
        {/if}
        <li class="{if $current == 'mes_infos'} current{elseif $current_parent == 'mes_infos'} current_parent{/if}">
            <a href="{$admin_url}mes_infos.php"><b class="icn">👤</b><i> Mes infos personnelles</i></a>

Modified src/templates/admin/config/_menu.tpl from [23c20c4779] to [ff6a70ffdf].

1
2
3
4
5
6
7
8
9
10
11
12
13
<nav class="tabs">
	<ul>
		<li{if $current == 'index'} class="current"{/if}><a href="{$admin_url}config/">Général</a></li>
		<li{if $current == 'categories'} class="current"{/if}><a href="{$admin_url}config/categories/">Catégories de membres</a></li>
		<li{if $current == 'fiches_membres'} class="current"{/if}><a href="{$admin_url}config/membres.php">Fiche des membres</a></li>
		<li{if $current == 'site'} class="current"{/if}><a href="{$admin_url}config/site.php">Site public</a></li>
		<li{if $current == 'donnees'} class="current"{/if}><a href="{$admin_url}config/donnees/">Sauvegarde et restauration</a></li>
		<li{if $current == 'plugins'} class="current"{/if}><a href="{$admin_url}config/plugins.php">Extensions</a></li>
		{if ENABLE_TECH_DETAILS}
		<li{if $current == 'logs'} class="current"{/if}><a href="{$admin_url}config/logs.php?type=errors">Journaux</a></li>
		{/if}
	</ul>
</nav>





<







1
2
3
4
5

6
7
8
9
10
11
12
<nav class="tabs">
	<ul>
		<li{if $current == 'index'} class="current"{/if}><a href="{$admin_url}config/">Général</a></li>
		<li{if $current == 'categories'} class="current"{/if}><a href="{$admin_url}config/categories/">Catégories de membres</a></li>
		<li{if $current == 'fiches_membres'} class="current"{/if}><a href="{$admin_url}config/membres.php">Fiche des membres</a></li>

		<li{if $current == 'donnees'} class="current"{/if}><a href="{$admin_url}config/donnees/">Sauvegarde et restauration</a></li>
		<li{if $current == 'plugins'} class="current"{/if}><a href="{$admin_url}config/plugins.php">Extensions</a></li>
		{if ENABLE_TECH_DETAILS}
		<li{if $current == 'logs'} class="current"{/if}><a href="{$admin_url}config/logs.php?type=errors">Journaux</a></li>
		{/if}
	</ul>
</nav>

Modified src/templates/web/config.tpl from [2454b9048e] to [31bee0260a].

1










2
3
4
5
6
7
8
9
10
11
12
13
{include file="admin/_head.tpl" title="Configuration — Site public" current="config"}











{form_errors}

{include file="admin/config/_menu.tpl" current="site"}

{if $config.desactiver_site}
    <div class="block alert">
        <h3>Site public désactivé</h3>
        <p>Le site public est désactivé, les visiteurs sont redirigés automatiquement vers la page de connexion.</p>
        <form method="post" action="{$self_url}">
            <p class="submit">
                {csrf_field key="config_site"}
|
>
>
>
>
>
>
>
>
>
>



<
<







1
2
3
4
5
6
7
8
9
10
11
12
13
14


15
16
17
18
19
20
21
{include file="admin/_head.tpl" title="Configuration" current="web"}

<nav class="tabs">
	<ul>
		<li><a href="./">Gestion du site web</a></li>
		{if $session->canAccess($session::SECTION_WEB, Membres::DROIT_ADMIN)}
			{*<li><a href="theme.php">Thèmes</a></li>*}
			<li class="current"><a href="config.php">Configuration</a></li>
		{/if}
	</ul>
</nav>

{form_errors}



{if $config.desactiver_site}
    <div class="block alert">
        <h3>Site public désactivé</h3>
        <p>Le site public est désactivé, les visiteurs sont redirigés automatiquement vers la page de connexion.</p>
        <form method="post" action="{$self_url}">
            <p class="submit">
                {csrf_field key="config_site"}
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
            <dd class="help">
                En désactivant le site public, les visiteurs seront automatiquement redirigés vers la page de connexion.<br />
                Cette option est utile si vous avez déjà un site web et ne souhaitez pas utiliser la fonctionnalité site web de Garradin.
            </dd>
        </dl>
    </fieldset>

    <fieldset>
        <legend>Gérer le contenu du site public</legend>
        <p class="help">
            Le contenu affiché sur le site est celui présent dans le wiki, il suffit de sélectionner «&nbsp;Cette page est visible sur le site de l'association&nbsp;» à l'édition d'une page wiki. Il est également possible de <a href="{$admin_url}wiki/creer.php?public">créer une nouvelle page publique sur le wiki</a>.
        </p>
    </fieldset>

    <form method="post" action="{$self_url}">
    <fieldset class="templatesList">
        <legend>Squelettes du site</legend>

        {if $reset_ok}
        <p class="block confirm">
            Réinitialisation effectuée. Les squelettes ont été remis à jour







<
<
<
<
<
<
<







69
70
71
72
73
74
75







76
77
78
79
80
81
82
            <dd class="help">
                En désactivant le site public, les visiteurs seront automatiquement redirigés vers la page de connexion.<br />
                Cette option est utile si vous avez déjà un site web et ne souhaitez pas utiliser la fonctionnalité site web de Garradin.
            </dd>
        </dl>
    </fieldset>








    <form method="post" action="{$self_url}">
    <fieldset class="templatesList">
        <legend>Squelettes du site</legend>

        {if $reset_ok}
        <p class="block confirm">
            Réinitialisation effectuée. Les squelettes ont été remis à jour
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
                    <td></td>
                </tr>
            </thead>
            <tbody>
            {foreach from=$sources key="source" item="local"}
                <tr>
                    <td>{if $local && $local.dist}<input type="checkbox" name="select[]" value="{$source}" id="f_source_{$iteration}" /><label for="f_source_{$iteration}"></label>{/if}</td>
                    <th><a href="{$admin_url}config/site.php?edit={$source|escape:'url'}" title="Éditer">{$source}</a></th>
                    <td>{if $local}{$local.mtime|date_fr:'d/m/Y à H:i:s'}{else}<em>(fichier non modifié)</em>{/if}</td>
                    <td class="actions">
                        {linkbutton shape="edit" label="Éditer" href="?edit=%s"|args:$source}
                    </td>
                </tr>
            {/foreach}
            </tbody>







|







92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
                    <td></td>
                </tr>
            </thead>
            <tbody>
            {foreach from=$sources key="source" item="local"}
                <tr>
                    <td>{if $local && $local.dist}<input type="checkbox" name="select[]" value="{$source}" id="f_source_{$iteration}" /><label for="f_source_{$iteration}"></label>{/if}</td>
					<th><a href="?edit={$source|escape:'url'}" title="Éditer">{$source}</a></th>
                    <td>{if $local}{$local.mtime|date_fr:'d/m/Y à H:i:s'}{else}<em>(fichier non modifié)</em>{/if}</td>
                    <td class="actions">
                        {linkbutton shape="edit" label="Éditer" href="?edit=%s"|args:$source}
                    </td>
                </tr>
            {/foreach}
            </tbody>

Modified src/templates/web/edit.tpl from [e7b8181d06] to [08595d53aa].

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
		<dl>
			{input type="text" name="title" source=$page required=true label="Titre"}
			{input type="text" name="uri" source=$page required=true label="Adresse unique URI" help="Utilisée pour désigner l'adresse de la page sur le site. Ne peut comporter que des lettres, des chiffres, des tirets et des tirets bas." pattern="[A-Za-z0-9_-]+"}
			{input type="list" name="parent_id" label="Catégorie" default=$parent target="web/_selector.php?parent=%d"|args:$page.parent_id required=true}
			{input type="datetime" name="date" label="Date" required=true default=$page->file()->created}
			<dt>Statut</dt>
			{input type="radio" name="status" value=$page::STATUS_ONLINE label="En ligne" source=$page}
			{input type="radio" name="status" value=$page::STATUS_DRAFT label="Brouillon" source=$page}
		</dl>
	</fieldset>

	<fieldset class="wikiEncrypt">
		<dl>
			<dt>
				<input type="checkbox" name="encryption" id="f_encryption" {if $encrypted} checked="checked"{/if} value="1" onchange="checkEncryption(this);" />







|







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
		<dl>
			{input type="text" name="title" source=$page required=true label="Titre"}
			{input type="text" name="uri" source=$page required=true label="Adresse unique URI" help="Utilisée pour désigner l'adresse de la page sur le site. Ne peut comporter que des lettres, des chiffres, des tirets et des tirets bas." pattern="[A-Za-z0-9_-]+"}
			{input type="list" name="parent_id" label="Catégorie" default=$parent target="web/_selector.php?parent=%d"|args:$page.parent_id required=true}
			{input type="datetime" name="date" label="Date" required=true default=$page->file()->created}
			<dt>Statut</dt>
			{input type="radio" name="status" value=$page::STATUS_ONLINE label="En ligne" source=$page}
			{input type="radio" name="status" value=$page::STATUS_DRAFT label="Brouillon" source=$page help="ne sera pas visible sur le site"}
		</dl>
	</fieldset>

	<fieldset class="wikiEncrypt">
		<dl>
			<dt>
				<input type="checkbox" name="encryption" id="f_encryption" {if $encrypted} checked="checked"{/if} value="1" onchange="checkEncryption(this);" />

Modified src/www/admin/static/scripts/code_editor.min.js from [f838117490] to [b81debcc16].

1
2
window.textEditor=function(t){if(!document.getElementById(t))throw new Error("Invalid ID parameter: "+t);return this.id=t,this.textarea=document.getElementById(t),this.shortcuts=[],"selectionStart"in this.textarea&&(this.textarea.addEventListener("keydown",this.keyEvent.bind(this),!0),this.textarea.addEventListener("keypress",this.keyEvent.bind(this),!0),!0)},textEditor.prototype.keyEvent=function(t){for(var e in t=t||window.event,this.shortcuts){var r=this.shortcuts[e];if(!t.metaKey&&!(t.ctrlKey&&!r.ctrl||r.ctrl&&!t.ctrlKey)&&!(t.shiftKey&&!r.shift||r.shift&&!t.shiftKey)&&!(t.altKey&&!r.alt||r.alt&&!t.altKey)&&(e=this.matchKeyPress(r.key,t))){if("function"==typeof r.callback)return!r.callback.call(this,t,e)||this.preventDefault(t);var n=(r.ctrl?"Ctrl-":"")+(r.alt?"Alt-":"");throw n+=(r.shift?"Shift-":"")+r,new Error("Invalid callback type for shortcut "+n)}}return!0},textEditor.prototype.matchKeyPress=function(t,e){return!(e.defaultPrevented||!e.key)&&(t=t.toLowerCase(),e.key.toLowerCase()==t&&t)},textEditor.prototype.preventDefault=function(t){return t.preventDefault&&t.preventDefault(),t.stopPropagation&&t.stopPropagation(),t.stopImmediatePropagation&&t.stopImmediatePropagation(),t.returnValue=!1,!(t.cancelBubble=!0)},textEditor.prototype.getSelection=function(){var t=this.textarea,e=t.selectionEnd-t.selectionStart;return{start:t.selectionStart,end:t.selectionEnd,length:e,text:t.value.substr(t.selectionStart,e)}},textEditor.prototype.replaceSelection=function(t,e){var r=this.textarea,n=t.start,o=n+e.length;return r.value=r.value.substr(0,n)+e+r.value.substr(t.end,r.value.length),this.setSelection(n,o),{start:n,end:o,length:e.length,text:e}},textEditor.prototype.insertAtPosition=function(t,e,r){var n=t+e.length,o=this.textarea;return o.value=o.value.substr(0,t)+e+o.value.substr(t,o.value.length-t),r||(r=n),this.setSelection(r,r)},textEditor.prototype.setSelection=function(t,e){var r=this.textarea;return r.focus(),r.selectionStart=t,r.selectionEnd=e,this.getSelection()},textEditor.prototype.scrollToSelection=function(t){var e=this.textarea,r=e.value.substr(t.end);e.value=e.value.substr(0,t.end),e.scrollTop=1e5;var n=e.scrollTop;e.value+=r,e.scrollTop=n,this.setSelection(t.start,t.end)},textEditor.prototype.wrapSelection=function(t,e,r){var n=this.textarea,o=n.scrollTop,a=t.text;return t=this.replaceSelection(t,e+a+r),""==a&&(t=this.setSelection(t.start+e.length,t.start+e.length)),n.scrollTop=o,t};
String.prototype.repeat=function(t){return new Array(t+1).join(this)},window.codeEditor=function(t){if(!textEditor.call(this,t))return!1;this.onlinechange=null,this.onlinenumberchange=null,this.fullscreen=!1,this.nb_lines=0,this.current_line=0,this.search_str=null,this.search_pos=0,this.params={indent_size:4,tab_size:4,convert_tabs:!0,lang:{search:"Text to search?\n(regexps allowed, begin them with '/')",replace:"Text for replacement?\n(use $1, $2... for regexp replacement)",search_selection:"Text to replace in selection?\n(regexps allowed, begin them with '/')",replace_result:"%d occurence found and replaced.",goto:"Line to go to:",no_search_result:"No search result found."}},(that=this).init(),this.textarea.spellcheck=!1,this.shortcuts.push({shift:!0,key:"tab",callback:this.indent}),this.shortcuts.push({key:"tab",callback:this.indent}),this.shortcuts.push({ctrl:!0,key:"f",callback:this.search}),this.shortcuts.push({ctrl:!0,key:"h",callback:this.searchAndReplace}),this.shortcuts.push({ctrl:!0,key:"g",callback:this.goToLine}),this.shortcuts.push({key:"F3",callback:this.searchNext}),this.shortcuts.push({key:"backspace",callback:this.backspace}),this.shortcuts.push({key:"enter",callback:this.enter}),this.shortcuts.push({key:'"',callback:this.insertBrackets}),this.shortcuts.push({key:"[",callback:this.insertBrackets}),this.shortcuts.push({key:"{",callback:this.insertBrackets}),this.shortcuts.push({key:"(",callback:this.insertBrackets}),this.shortcuts.push({key:"F11",callback:this.toggleFullscreen}),this.textarea.addEventListener("keypress",this.keyEvent.bind(this),!0),this.textarea.addEventListener("keydown",this.keyEvent.bind(this),!0)},codeEditor.prototype=function(t){function e(){}return e.prototype=t,new e}(textEditor.prototype),codeEditor.prototype.init=function(){var t=this;for(this.nb_lines=this.countLines(),this.parent=document.createElement("div"),this.parent.className="codeEditor",this.lineCounter=document.createElement("span"),this.lineCounter.className="lineCount",i=1;i<=this.nb_lines;i++)this.lineCounter.innerHTML+="<b>"+i+"</b>";this.lineCounter.innerHTML+="<i>---</i>",this.parent.appendChild(this.lineCounter);var e=document.createElement("div");e.className="container",e.appendChild(this.textarea.cloneNode(!0)),this.parent.appendChild(e);var s=this.textarea.parentNode;s.appendChild(this.parent),s.removeChild(this.textarea),this.textarea=this.parent.getElementsByTagName("textarea")[0],this.textarea.wrap="off",this.params.convert_tabs&&(this.textarea.value=this.textarea.value.replace(/[ ]{1,7}\t/g," ".repeat(this.params.tab_size)),this.textarea.value=this.textarea.value.replace(/\t/g," ".repeat(this.params.tab_size))),this.textarea.addEventListener("focus",function(){t.update()},!1),this.textarea.addEventListener("keyup",function(){t.update()},!1),this.textarea.addEventListener("click",function(){t.update()},!1),this.textarea.addEventListener("scroll",function(){t.lineCounter.scrollTop=t.textarea.scrollTop},!1)},codeEditor.prototype.update=function(){var t=this.getSelection(),e=this.getLineNumberFromPosition(t),s=this.countLines();if(this.search_pos=t.end,s!=this.nb_lines){for(var r=this.lineCounter.getElementsByTagName("b"),i=this.nb_lines;s<i;i--)this.lineCounter.removeChild(r[i-1]);var n=this.lineCounter.lastChild;for(i=r.length;i<s;i++){var a=document.createElement("b");a.innerHTML=i+1,this.lineCounter.insertBefore(a,n)}this.nb_lines=s,"function"==typeof this.onlinenumberchange&&this.onlinenumberchange.call(this)}if(e!=this.current_line){for(r=this.lineCounter.getElementsByTagName("b"),i=0;i<this.nb_lines;i++)r[i].className="";r[e].className="current",this.current_line=e,"function"==typeof this.onlinechange&&this.onlinechange.call(this)}},codeEditor.prototype.countLines=function(){var t=this.textarea.value.match(/(\r?\n)/g);return t?t.length+1:1},codeEditor.prototype.getLineNumberFromPosition=function(t){if(0==(t=t||this.getSelection()).start)return 0;var e=this.textarea.value.substr(0,t.start).match(/(\r?\n)/g);return e?e.length:0},codeEditor.prototype.getLines=function(){return this.textarea.value.split("\n")},codeEditor.prototype.getLine=function(t){return this.textarea.value.split("\n",t+1)[t]},codeEditor.prototype.getLinePosition=function(t,e){var s=0;for(i=0;i<t.length;i++){if(i==e)return{start:s+i,end:s+t[i].length,length:t[i].length,text:t[i]};s+=t[i].length}return!1},codeEditor.prototype.selectLines=function(t){for(var e=t.start;0<e;e--)if("\n"==this.textarea.value.substr(e,1)){t.start=e+1;break}for(e=t.end-1;e<this.textarea.length;e++)if("\n"==this.textarea.value.substr(e,1)){t.end=e-1;break}return this.setSelection(t.start,t.end),t},codeEditor.prototype.goToLine=function(t){var e=window.prompt(that.params.lang.goto);if(e){var s=this.textarea.value.split("\n",parseInt(e,10)).join("\n").length;return this.scrollToSelection(this.setSelection(s,s)),!0}},codeEditor.prototype.indent=function(t,e){var s=this.getSelection(),r=t.shiftKey,i=this.getLines(),n=this.getLineNumberFromPosition(s),a=this.getLinePosition(i,n),h=s.end>a.end;if((0==s.length||!h)&&s.start!=a.start)return this.insertAtPosition(s.start," ".repeat(this.params.indent_size)),!0;if(0==s.length&&s.start==a.start){var o=n-1 in i&&i[n-1].match(/^(\s+)/);if(o&&0==a.length)c=" ".repeat(o[1].length);else var c=" ".repeat(this.params.indent_size);return this.insertAtPosition(s.start,c),!0}s=this.selectLines(s);var l=this.textarea.value.substr(s.start,s.end-s.start);if(i=l.split("\n"),r)for(var p=new RegExp("^[ ]{1,"+this.params.indent_size+"}"),u=0;u<i.length;u++)i[u]=i[u].replace(p,"");else for(u=0;u<i.length;u++)i[u]=" ".repeat(this.params.indent_size)+i[u];return l=i.join("\n"),this.replaceSelection(s,l),!0},codeEditor.prototype.search=function(){if(this.search_str=window.prompt(this.params.lang.search,this.search_str))return this.search_pos=0,this.searchNext()},codeEditor.prototype.searchNext=function(){if(!this.search_str)return!0;var t=this.getSelection(),e=t.end>=this.search_pos?this.search_pos:t.start,s=this.textarea.value.substr(e),r=this.getSearchRegexp(this.search_str),i=s.search(r);if(-1==i)return window.alert(this.params.lang.no_search_result);var n=s.match(r);return t.start=e+i,t.end=t.start+n[0].length,t.length=n[0].length,t.text=n[0],this.setSelection(t.start,t.end),this.search_pos=t.end,this.scrollToSelection(t),!0},codeEditor.prototype.getSearchRegexp=function(t,e){var s,r;if("/"==t.substr(0,1)){var i=t.lastIndexOf("/");s=t.substr(1,i-1),r=t.substr(i+1).replace(/g/,"")}else s=t.replace(/([\/$^.?()[\]{}\\])/,"\\$1"),r="i";return e&&(r+="g"),new RegExp(s,r)},codeEditor.prototype.searchAndReplace=function(t){var e=this.getSelection(),i=0!=e.length?this.params.lang.search_selection:this.params.lang.search;if(!(s=window.prompt(i,this.search_str))||!(r=window.prompt(that.params.lang.replace)))return!0;var n=this.getSearchRegexp(s,!0);if(0==e.length){var a=this.textarea.value.match(n).length;this.textarea.value=this.textarea.value.replace(n,r)}else a=e.text.match(n).length,this.replaceSelection(e,e.text.replace(n,r));return window.alert(this.params.lang.replace_result.replace(/%d/g,a)),!0},codeEditor.prototype.enter=function(t){var e=this.getSelection(),s=this.getLineNumberFromPosition(e),r="";return s=this.getLine(s),"{"==this.textarea.value.substr(e.start-1,1)&&(r+=" ".repeat(this.params.indent_size)),(match=s.match(/^(\s+)/))&&(r+=match[1]),!!r&&(this.insertAtPosition(e.start,"\n"+r),!0)},codeEditor.prototype.backspace=function(t){var e=this.getSelection();if(0<e.length)return!1;if('""'==(s=this.textarea.value.substr(e.start-2,2))||"''"==s||"{}"==s||"()"==s||"[]"==s)return e.start-=2,this.replaceSelection(e,""),!0;var s=this.textarea.value.substr(e.start-20,20);return-1!=(pos=s.search(/^(\s+)$/m))&&(e.start-=this.params.indent_size,this.replaceSelection(e,""),!0)},codeEditor.prototype.insertBrackets=function(t,e){var s=this.getSelection(),r=e,i=r;switch(r){case"(":i=")";break;case"[":i="]";break;case"{":i="}"}return 0==s.length?this.insertAtPosition(s.start,r+i,s.start+1):this.wrapSelection(s,r,i),!0},codeEditor.prototype.toggleFullscreen=function(t){for(var e=this.parent.className.split(" "),s=0;s<e.length;s++)if("fullscreen"==e[s])return e.splice(s,1),this.parent.className=e.join(" "),!(this.fullscreen=!1);return e.push("fullscreen"),this.parent.className=e.join(" "),this.fullscreen=!0};

|
1
2
window.textEditor=function(t){if(!document.getElementById(t))throw new Error("Invalid ID parameter: "+t);return this.id=t,this.textarea=document.getElementById(t),this.shortcuts=[],"selectionStart"in this.textarea&&(this.textarea.addEventListener("keydown",this.keyEvent.bind(this),!0),this.textarea.addEventListener("keypress",this.keyEvent.bind(this),!0),!0)},textEditor.prototype.keyEvent=function(t){for(var e in t=t||window.event,this.shortcuts){var r=this.shortcuts[e];if(!t.metaKey&&!(t.ctrlKey&&!r.ctrl||r.ctrl&&!t.ctrlKey)&&!(t.shiftKey&&!r.shift||r.shift&&!t.shiftKey)&&!(t.altKey&&!r.alt||r.alt&&!t.altKey)&&(e=this.matchKeyPress(r.key,t))){if("function"==typeof r.callback)return!r.callback.call(this,t,e)||this.preventDefault(t);var n=(r.ctrl?"Ctrl-":"")+(r.alt?"Alt-":"");throw n+=(r.shift?"Shift-":"")+r,new Error("Invalid callback type for shortcut "+n)}}return!0},textEditor.prototype.matchKeyPress=function(t,e){return!(e.defaultPrevented||!e.key)&&(t=t.toLowerCase(),e.key.toLowerCase()==t&&t)},textEditor.prototype.preventDefault=function(t){return t.preventDefault&&t.preventDefault(),t.stopPropagation&&t.stopPropagation(),t.stopImmediatePropagation&&t.stopImmediatePropagation(),t.returnValue=!1,!(t.cancelBubble=!0)},textEditor.prototype.getSelection=function(){var t=this.textarea,e=t.selectionEnd-t.selectionStart;return{start:t.selectionStart,end:t.selectionEnd,length:e,text:t.value.substr(t.selectionStart,e)}},textEditor.prototype.replaceSelection=function(t,e){var r=this.textarea,n=t.start,o=n+e.length;return r.value=r.value.substr(0,n)+e+r.value.substr(t.end,r.value.length),this.setSelection(n,o),{start:n,end:o,length:e.length,text:e}},textEditor.prototype.insertAtPosition=function(t,e,r){var n=t+e.length,o=this.textarea;return o.value=o.value.substr(0,t)+e+o.value.substr(t,o.value.length-t),r||(r=n),this.setSelection(r,r)},textEditor.prototype.setSelection=function(t,e){var r=this.textarea;return r.focus(),r.selectionStart=t,r.selectionEnd=e,this.getSelection()},textEditor.prototype.scrollToSelection=function(t){var e=this.textarea,r=e.value.substr(t.end);e.value=e.value.substr(0,t.end),e.scrollTop=1e5;var n=e.scrollTop;e.value+=r,e.scrollTop=n,this.setSelection(t.start,t.end)},textEditor.prototype.wrapSelection=function(t,e,r){var n=this.textarea,o=n.scrollTop,a=t.text;return t=this.replaceSelection(t,e+a+r),""==a&&(t=this.setSelection(t.start+e.length,t.start+e.length)),n.scrollTop=o,t};
String.prototype.repeat=function(t){return new Array(t+1).join(this)},window.codeEditor=function(t){if(!textEditor.call(this,t))return!1;this.onlinechange=null,this.onlinenumberchange=null,this.fullscreen=!1,this.nb_lines=0,this.current_line=0,this.search_str=null,this.search_pos=0,this.params={indent_size:4,tab_size:4,convert_tabs:!0,lang:{search:"Text to search?\n(regexps allowed, begin them with '/')",replace:"Text for replacement?\n(use $1, $2... for regexp replacement)",search_selection:"Text to replace in selection?\n(regexps allowed, begin them with '/')",replace_result:"%d occurence found and replaced.",goto:"Line to go to:",no_search_result:"No search result found."}},(that=this).init(),this.textarea.spellcheck=!1,this.shortcuts.push({shift:!0,key:"tab",callback:this.indent}),this.shortcuts.push({key:"tab",callback:this.indent}),this.shortcuts.push({ctrl:!0,key:"f",callback:this.search}),this.shortcuts.push({ctrl:!0,key:"h",callback:this.searchAndReplace}),this.shortcuts.push({ctrl:!0,key:"g",callback:this.goToLine}),this.shortcuts.push({key:"F3",callback:this.searchNext}),this.shortcuts.push({key:"backspace",callback:this.backspace}),this.shortcuts.push({key:"enter",callback:this.enter}),this.shortcuts.push({key:'"',callback:this.insertBrackets}),this.shortcuts.push({key:"[",callback:this.insertBrackets}),this.shortcuts.push({key:"{",callback:this.insertBrackets}),this.shortcuts.push({key:"(",callback:this.insertBrackets}),this.shortcuts.push({key:"F11",callback:this.toggleFullscreen}),this.textarea.addEventListener("keypress",this.keyEvent.bind(this),!0),this.textarea.addEventListener("keydown",this.keyEvent.bind(this),!0)},codeEditor.prototype=function(t){function e(){}return e.prototype=t,new e}(textEditor.prototype),codeEditor.prototype.init=function(){var t=this;for(this.nb_lines=this.countLines(),this.parent=document.createElement("div"),this.parent.className="codeEditor",this.lineCounter=document.createElement("span"),this.lineCounter.className="lineCount",i=1;i<=this.nb_lines;i++)this.lineCounter.innerHTML+="<b>"+i+"</b>";this.lineCounter.innerHTML+="<i>---</i>",this.parent.appendChild(this.lineCounter);var e=document.createElement("div");e.className="container",e.appendChild(this.textarea.cloneNode(!0)),this.parent.appendChild(e);var s=this.textarea.parentNode;s.appendChild(this.parent),s.removeChild(this.textarea),this.textarea=this.parent.getElementsByTagName("textarea")[0],this.textarea.wrap="off",this.params.convert_tabs&&(this.textarea.value=this.textarea.value.replace(/[ ]{1,7}\t/g," ".repeat(this.params.tab_size)),this.textarea.value=this.textarea.value.replace(/\t/g," ".repeat(this.params.tab_size))),this.textarea.addEventListener("focus",function(){t.update()},!1),this.textarea.addEventListener("keyup",function(){t.update()},!1),this.textarea.addEventListener("click",function(){t.update()},!1),this.textarea.addEventListener("scroll",function(){t.lineCounter.scrollTop=t.textarea.scrollTop},!1)},codeEditor.prototype.update=function(){var t=this.getSelection(),e=this.getLineNumberFromPosition(t),s=this.countLines();if(this.search_pos=t.end,s!=this.nb_lines){for(var r=this.lineCounter.getElementsByTagName("b"),i=this.nb_lines;s<i;i--)this.lineCounter.removeChild(r[i-1]);var n=this.lineCounter.lastChild;for(i=r.length;i<s;i++){var a=document.createElement("b");a.innerHTML=i+1,this.lineCounter.insertBefore(a,n)}this.nb_lines=s,"function"==typeof this.onlinenumberchange&&this.onlinenumberchange.call(this)}if(e!=this.current_line){for(r=this.lineCounter.getElementsByTagName("b"),i=0;i<this.nb_lines;i++)r[i].className="";r[e].className="current",this.current_line=e,"function"==typeof this.onlinechange&&this.onlinechange.call(this)}},codeEditor.prototype.countLines=function(){var t=this.textarea.value.match(/(\r?\n)/g);return t?t.length+1:1},codeEditor.prototype.getLineNumberFromPosition=function(t){if(0==(t=t||this.getSelection()).start)return 0;var e=this.textarea.value.substr(0,t.start).match(/(\r?\n)/g);return e?e.length:0},codeEditor.prototype.getLines=function(){return this.textarea.value.split("\n")},codeEditor.prototype.getLine=function(t){return this.textarea.value.split("\n",t+1)[t]},codeEditor.prototype.getLinePosition=function(t,e){var s=0;for(i=0;i<t.length;i++){if(i==e)return{start:s+i,end:s+t[i].length,length:t[i].length,text:t[i]};s+=t[i].length}return!1},codeEditor.prototype.selectLines=function(t){for(var e=t.start;0<e;e--)if("\n"==this.textarea.value.substr(e,1)){t.start=e+1;break}for(e=t.end-1;e<this.textarea.length;e++)if("\n"==this.textarea.value.substr(e,1)){t.end=e-1;break}return this.setSelection(t.start,t.end),t},codeEditor.prototype.goToLine=function(t){var e=window.prompt(that.params.lang.goto);if(e){var s=this.textarea.value.split("\n",parseInt(e,10)).join("\n").length;return this.scrollToSelection(this.setSelection(s,s)),!0}},codeEditor.prototype.indent=function(t,e){var s=this.getSelection(),r=t.shiftKey,i=this.getLines(),n=this.getLineNumberFromPosition(s),a=this.getLinePosition(i,n),h=s.end>a.end;if((0==s.length||!h)&&s.start!=a.start)return this.insertAtPosition(s.start," ".repeat(this.params.indent_size)),!0;if(0==s.length&&s.start==a.start){var o=n-1 in i&&i[n-1].match(/^(\s+)/);if(o&&0==a.length)c=" ".repeat(o[1].length);else var c=" ".repeat(this.params.indent_size);return this.insertAtPosition(s.start,c),!0}s=this.selectLines(s);var l=this.textarea.value.substr(s.start,s.end-s.start);if(i=l.split("\n"),r)for(var p=new RegExp("^[ ]{1,"+this.params.indent_size+"}"),u=0;u<i.length;u++)i[u]=i[u].replace(p,"");else for(u=0;u<i.length;u++)i[u]=" ".repeat(this.params.indent_size)+i[u];return l=i.join("\n"),this.replaceSelection(s,l),!0},codeEditor.prototype.search=function(){if(this.search_str=window.prompt(this.params.lang.search,this.search_str?this.search_str:""))return this.search_pos=0,this.searchNext()},codeEditor.prototype.searchNext=function(){if(!this.search_str)return!0;var t=this.getSelection(),e=t.end>=this.search_pos?this.search_pos:t.start,s=this.textarea.value.substr(e),r=this.getSearchRegexp(this.search_str),i=s.search(r);if(-1==i)return window.alert(this.params.lang.no_search_result);var n=s.match(r);return t.start=e+i,t.end=t.start+n[0].length,t.length=n[0].length,t.text=n[0],this.setSelection(t.start,t.end),this.search_pos=t.end,this.scrollToSelection(t),!0},codeEditor.prototype.getSearchRegexp=function(t,e){var s,r;if("/"==t.substr(0,1)){var i=t.lastIndexOf("/");s=t.substr(1,i-1),r=t.substr(i+1).replace(/g/,"")}else s=t.replace(/([\/$^.?()[\]{}\\])/,"\\$1"),r="i";return e&&(r+="g"),new RegExp(s,r)},codeEditor.prototype.searchAndReplace=function(t){var e=this.getSelection(),i=0!=e.length?this.params.lang.search_selection:this.params.lang.search;if(!(s=window.prompt(i,this.search_str?this.search_str:""))||!(r=window.prompt(that.params.lang.replace)))return!0;var n=this.getSearchRegexp(s,!0);if(0==e.length){var a=this.textarea.value.match(n).length;this.textarea.value=this.textarea.value.replace(n,r)}else a=e.text.match(n).length,this.replaceSelection(e,e.text.replace(n,r));return window.alert(this.params.lang.replace_result.replace(/%d/g,a)),!0},codeEditor.prototype.enter=function(t){var e=this.getSelection(),s=this.getLineNumberFromPosition(e),r="";return s=this.getLine(s),"{"==this.textarea.value.substr(e.start-1,1)&&(r+=" ".repeat(this.params.indent_size)),(match=s.match(/^(\s+)/))&&(r+=match[1]),!!r&&(this.insertAtPosition(e.start,"\n"+r),!0)},codeEditor.prototype.backspace=function(t){var e=this.getSelection();if(0<e.length)return!1;if('""'==(s=this.textarea.value.substr(e.start-2,2))||"''"==s||"{}"==s||"()"==s||"[]"==s)return e.start-=2,this.replaceSelection(e,""),!0;var s=this.textarea.value.substr(e.start-20,20);return-1!=(pos=s.search(/^(\s+)$/m))&&(e.start-=this.params.indent_size,this.replaceSelection(e,""),!0)},codeEditor.prototype.insertBrackets=function(t,e){var s=this.getSelection(),r=e,i=r;switch(r){case"(":i=")";break;case"[":i="]";break;case"{":i="}"}return 0==s.length?this.insertAtPosition(s.start,r+i,s.start+1):this.wrapSelection(s,r,i),!0},codeEditor.prototype.toggleFullscreen=function(t){for(var e=this.parent.className.split(" "),s=0;s<e.length;s++)if("fullscreen"==e[s])return e.splice(s,1),this.parent.className=e.join(" "),!(this.fullscreen=!1);return e.push("fullscreen"),this.parent.className=e.join(" "),this.fullscreen=!0};

Modified src/www/admin/static/scripts/skel_editor.css from [f204b32def] to [7c23f5ec10].

27
28
29
30
31
32
33

34
35
36
37
38
39
40
}

.codeEditor .sk_toolbar select {
	float: right;
	border: none;
	border-radius: .2em;
	height: 24px;

	padding-left: 24px;
	margin: 4px .5em;
	background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAMFBMVEUAAACZm4leYFyOkX1RU09MTkp9f2+ys6KwsZrn5+KanIz///+6u6vGxryDhXtVV1Otpz1oAAAAA3RSTlMA+7omiqY6AAAAgklEQVQI12NI+f9fgQEEfO7e+QBm/BGU+P8fJPrd2LgLCD4AGSCBLCDD8Pfu3bu9QCK/Z86e/esDw4/Hv+/euf0ZyEj7PXPnbCDDI+33kZDQkE8M/11D1969e9eEwRNIlpe332f421Ne0dHRcYnh75k7Z8/cudPEoOIS4uriAlQMAwDpN0taA/g97gAAAABJRU5ErkJggg==") no-repeat 5px center;
	cursor: pointer;
}

.codeEditor .sk_toolbar select:hover {







>







27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
}

.codeEditor .sk_toolbar select {
	float: right;
	border: none;
	border-radius: .2em;
	height: 24px;
	padding: 1px;
	padding-left: 24px;
	margin: 4px .5em;
	background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAMFBMVEUAAACZm4leYFyOkX1RU09MTkp9f2+ys6KwsZrn5+KanIz///+6u6vGxryDhXtVV1Otpz1oAAAAA3RSTlMA+7omiqY6AAAAgklEQVQI12NI+f9fgQEEfO7e+QBm/BGU+P8fJPrd2LgLCD4AGSCBLCDD8Pfu3bu9QCK/Z86e/esDw4/Hv+/euf0ZyEj7PXPnbCDDI+33kZDQkE8M/11D1969e9eEwRNIlpe332f421Ne0dHRcYnh75k7Z8/cudPEoOIS4uriAlQMAwDpN0taA/g97gAAAABJRU5ErkJggg==") no-repeat 5px center;
	cursor: pointer;
}

.codeEditor .sk_toolbar select:hover {

Modified src/www/admin/static/scripts/skel_editor.js from [6b35de296d] to [807c3cfad0].

114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
						e.target.options[i].selected = true;
					}
				}

				return false;
			}

			var url = garradin.admin_url + 'config/site.php?edit=' + encodeURIComponent(file);

			window.location.href = url + (code.fullscreen ? '#fullscreen' : '');

			return true;
		};

		code.resetFile = function (e)







|







114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
						e.target.options[i].selected = true;
					}
				}

				return false;
			}

			var url = '?edit=' + encodeURIComponent(file);

			window.location.href = url + (code.fullscreen ? '#fullscreen' : '');

			return true;
		};

		code.resetFile = function (e)

Modified src/www/admin/web/config.php from [4b2ceec322] to [57c41f518e].

1
2
3
4


5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70

71
<?php
namespace Garradin;

require_once __DIR__ . '/_inc.php';



if (f('desactiver_site') && $form->check('config_site'))
{
    $config->set('desactiver_site', true);
    $config->save();
    Utils::redirect(ADMIN_URL . 'config/site.php');
}
elseif (f('activer_site') && $form->check('config_site'))
{
    $config->set('desactiver_site', false);
    $config->save();
    Utils::redirect(ADMIN_URL . 'config/site.php');
}

if (f('select') && f('reset') && $form->check('squelettes'))
{
    try {
        foreach (f('select') as $source)
        {
            if (!Squelette::resetSource($source))
            {
                throw new UserException('Impossible de réinitialiser le squelette.');
            }
        }
    
        Utils::redirect(ADMIN_URL . 'config/site.php?reset_ok');
    }
    catch (UserException $e)
    {
        $form->addError($e->getMessage());
    }
}


if (qg('edit'))
{
    $source = Squelette::getSource(qg('edit'));

    if (null === $source)
    {
        throw new UserException("Ce squelette n'existe pas.");
    }

    $csrf_key = 'edit_skel_' . md5(qg('edit'));

    if (f('save') && $form->check($csrf_key))
    {
        if (Squelette::editSource(qg('edit'), f('content')))
        {
            $fullscreen = null !== qg('fullscreen') ? '#fullscreen' : '';
            Utils::redirect(ADMIN_URL . 'config/site.php?edit='.rawurlencode(qg('edit')).'&ok'.$fullscreen);
        }
        else
        {
            $form->addError("Impossible d'enregistrer le squelette.");
        }
    }

    $tpl->assign('edit', ['file' => trim(qg('edit')), 'content' => $source]);
    $tpl->assign('csrf_key', $csrf_key);
}

$tpl->assign('sources', Squelette::listSources());

$tpl->assign('reset_ok', qg('reset_ok') !== null);
$tpl->assign('ok', qg('ok') !== null);

$tpl->display('admin/config/site.tpl');




>
>





|





|


|
<
<







|
<
|
<
|
<
<
<
<
<
|
<









|
<



|



|

|









>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21


22
23
24
25
26
27
28
29

30

31





32

33
34
35
36
37
38
39
40
41
42

43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
<?php
namespace Garradin;

require_once __DIR__ . '/_inc.php';

$config = Config::getInstance();

if (f('desactiver_site') && $form->check('config_site'))
{
    $config->set('desactiver_site', true);
    $config->save();
	Utils::redirect(Utils::getSelfURI());
}
elseif (f('activer_site') && $form->check('config_site'))
{
    $config->set('desactiver_site', false);
    $config->save();
	Utils::redirect(Utils::getSelfURI());
}

$form->runIf('reset', function () {


        foreach (f('select') as $source)
        {
            if (!Squelette::resetSource($source))
            {
                throw new UserException('Impossible de réinitialiser le squelette.');
            }
        }
}, 'squelettes', Utils::getSelfURI('reset_ok'));









if (qg('edit')) {

    $source = Squelette::getSource(qg('edit'));

    if (null === $source)
    {
        throw new UserException("Ce squelette n'existe pas.");
    }

    $csrf_key = 'edit_skel_' . md5(qg('edit'));

	$form->runIf('save', function () {

        if (Squelette::editSource(qg('edit'), f('content')))
        {
            $fullscreen = null !== qg('fullscreen') ? '#fullscreen' : '';
			Utils::redirect(Utils::getSelfURI(sprintf('edit=%s&ok%s', rawurlencode(qg('edit')), $fullscreen)));
        }
        else
        {
			throw new UserException("Impossible d'enregistrer le squelette.");
        }
	}, $csrf_key);

    $tpl->assign('edit', ['file' => trim(qg('edit')), 'content' => $source]);
    $tpl->assign('csrf_key', $csrf_key);
}

$tpl->assign('sources', Squelette::listSources());

$tpl->assign('reset_ok', qg('reset_ok') !== null);
$tpl->assign('ok', qg('ok') !== null);

$tpl->display('web/config.tpl');