1{% extends project_specific|yesno:"baseprojectspecificpage.html,baseprojectpage.html" %}
2{% load projecttags %}
3{% load humanize %}
4
5{% block title %} BitBake variables - {{project.name}} - Toaster {% endblock %}
6{% block projectinfomain %}
7
8<h2>Bitbake variables</h2>
9<div>
10  <dl>
11    {% if distro_defined %}
12    <dt>
13    <span class="js-config-var-name js-config-var-managed-name">DISTRO</span>
14    <span class="glyphicon glyphicon-question-sign get-help" title="The short name of the distribution. If the variable is blank, meta/conf/distro/defaultsetup.conf will be used"></span>
15    </dt>
16    <dd class="variable-list">
17    <span class="lead" id="distro">{{distro}}</span>
18    <span class="glyphicon glyphicon-edit" id="change-distro-icon"></span>
19    <form id="change-distro-form" class="form-inline" style="display:none;">
20      <div id="edit-distro-name-div" class="form-group">
21        <input type="text" class="form-control" id="new-distro" value="{{distro}}">
22      </div>
23      <button id="apply-change-distro" class="btn btn-default" type="button">Save</button>
24      <button id="cancel-change-distro" type="button" class="btn btn-link">Cancel</button>
25      <span class="help-block" id="distro-error-message"></span>
26    </form>
27    </dd>
28    {% endif %}
29
30    {% if dl_dir_defined %}
31    <dt>
32    <span class="js-config-var-name js-config-var-managed-name">DL_DIR</span>
33    <span class="glyphicon glyphicon-question-sign get-help" title="Absolute path to the directory used to store downloads required for your builds. By default, Toaster projects share the same downloads directory"></span>
34    </dt>
35    <dd class="variable-list">
36    <span id="dl_dir" class="lead {% if not dl_dir %} text-muted {% endif %}">{% if dl_dir %}{{dl_dir}}{%else%}Not set{%endif%}</span>
37    <span class="glyphicon glyphicon-edit" id="change-dl_dir-icon"></span>
38    <form id="change-dl_dir-form" class="form-inline" style="display:none;">
39      <div class="form-group" id="validate-dl_dir">
40        <input type="text" class="form-control" id="new-dl_dir" placeholder="Type an absolute path">
41      </div>
42      <button id="apply-change-dl_dir" class="btn btn-default" type="button">Save</button>
43      <button id="cancel-change-dl_dir" type="button" class="btn btn-link">Cancel</button>
44      <p class="help-block" id="hintError-dl_dir" style="display:none;">The directory path cannot include spaces or any of these characters: \ ? % * : | " " &lt; &gt;</p>
45      <p class="help-block" id="hintError-initialChar-dl_dir" style="display:none;">The directory path should either start with a /, e.g. /home/toaster/downloads; or with a variable, e.g. ${TOPDIR}/downloads.</p>
46    </form>
47    </dd>
48    {% endif %}
49
50    {% if fstypes_defined %}
51    <dt>
52    <span class="js-config-var-name js-config-var-managed-name">IMAGE_FSTYPES</span>
53    <span class="glyphicon glyphicon-question-sign get-help" title="Formats of root file system images that you want to create"></span>
54    </dt>
55    <dd class="variable-list">
56    <span class="lead" id="image_fstypes">{{fstypes}}</span>
57    <span class="glyphicon glyphicon-edit" id="change-image_fstypes-icon"></span>
58    <form id="change-image_fstypes-form" style="display:none;">
59      <label>Type the image types you want to build:</label>
60      <div class="form-group form-inline" id="validate-image_fstypes">
61        <input type="text" class="form-control "id="new-imagefs_types">
62        <button id="apply-change-image_fstypes" type="button" class="btn btn-default">Save</button>
63        <button id="cancel-change-image_fstypes" type="button" class="btn btn-link">Cancel</button>
64      </div>
65      <p class="help-block text-danger" style="display:none;" id="hintError-image-fs_type">A valid image type cannot include underscores</p>
66      <p class="help-block text-danger" style="display:none;" id="fstypes-error-message">You must select at least one image type</p>
67      <label>Or choose from known image types:</label>
68      <input id="filter-image_fstypes" type="text" placeholder="Search image types" class="form-control">
69      <div id="all-image_fstypes" class="scrolling"></div>
70    </form>
71    </dd>
72    {% endif %}
73
74    {% if image_install_append_defined %}
75    <dt>
76    <span class="js-config-var-name js-config-var-managed-name">IMAGE_INSTALL:append</span>
77    <span class="glyphicon glyphicon-question-sign get-help" title="Specifies additional packages to install into an image. If your build creates more than one image, the packages will be installed in all of them"></span>
78    </dt>
79    <dd class="variable-list">
80    <span id="image_install" class="lead {% if not image_install_append %} text-muted {%endif%}">{% if image_install_append %}{{image_install_append}}{%else%}Not set{%endif%}</span>
81    <span class="glyphicon glyphicon-edit" id="change-image_install-icon"></span>
82    <span class="glyphicon glyphicon-trash" id="delete-image_install-icon" {% if image_install_append %}{%else%}style="display:none;"{%endif%}></span>
83    <form id="change-image_install-form" class="form-inline" style="display:none;">
84      <div class="row">
85        <div class="col-md-4">
86          <span class="help-block">To set IMAGE_INSTALL:append to more than one package, type the package names separated by a space.</span>
87        </div>
88      </div>
89      <div class="form-group">
90        <input type="text" class="form-control" id="new-image_install" placeholder="Type one or more package names">
91      </div>
92      <button id="apply-change-image_install" class="btn btn-default" type="button">Save</button>
93      <button id="cancel-change-image_install" type="button" class="btn btn-link">Cancel</button>
94    </form>
95    </dd>
96    {% endif %}
97
98    {% if package_classes_defined %}
99    <dt>
100    <span class="js-config-var-name js-config-var-managed-name">PACKAGE_CLASSES</span>
101    <span class="glyphicon glyphicon-question-sign get-help" title="Specifies the package manager to use when packaging data"></span>
102    </dt>
103    <dd class="variable-list">
104    <span class="lead" id="package_classes">{{package_classes}}</span>
105    <span id="change-package_classes-icon" class="glyphicon glyphicon-edit"></span>
106    <form id="change-package_classes-form" style="display:none;">
107      <div class="form-group">
108        <label class="control-label">
109          Root file system package format
110          <span class="glyphicon glyphicon-question-sign get-help" title="The package format used to generate the root file system. Options are <code>deb</code>, <code>ipk</code> and <code>rpm</code>"></i>
111        </label>
112        <select id="package_classes-select" class="form-control">
113          <option>package_deb</option>
114          <option>package_ipk</option>
115          <option>package_rpm</option>
116        </select>
117      </div>
118      <div class="form-group">
119        <label class="control-label">
120          Additional package formats
121          <span class="glyphicon glyphicon-question-sign get-help" title="Extra package formats to build"></span>
122        </label>
123        <div class="checkbox">
124          <label id="package_class_1">
125            <input type="checkbox" id="package_class_1_input"> package_deb
126          </label>
127        </div>
128        <div class="checkbox">
129          <label id="package_class_2">
130            <input type="checkbox" id="package_class_2_input"> package_ipk
131          </label>
132        </div>
133      </div>
134      <button id="apply-change-package_classes" type="button" class="btn btn-default">Save</button>
135      <button id="cancel-change-package_classes" type="button" class="btn btn-link">Cancel</button>
136    </form>
137    </dd>
138    {% endif %}
139
140    {% if sstate_dir_defined %}
141    <dt>
142    <span class="js-config-var-name js-config-var-managed-name">SSTATE_DIR</span>
143    <span class="glyphicon glyphicon-question-sign get-help" title="Absolute path to the directory used to store shared state cache files. These files are reused across the builds, which makes the builds faster. By default, Toaster projects share the same cache directory"></span>
144    </dt>
145    <dd class="variable-list">
146    <span id="sstate_dir" class="lead {% if not sstate_dir %} text-muted {% endif %}">{% if sstate_dir %}{{sstate_dir}}{%else%}Not set{%endif%}</span>
147    <span class="glyphicon glyphicon-edit" id="change-sstate_dir-icon"></span>
148    <form class="form-inline" id="change-sstate_dir-form" style="display:none;">
149      <div class="form-group" id="validate-sstate_dir">
150        <input type="text" class="form-control" id="new-sstate_dir" placeholder="Type an absolute path">
151      </div>
152      <button id="apply-change-sstate_dir" class="btn btn-default" type="button">Save</button>
153      <button id="cancel-change-sstate_dir" type="button" class="btn btn-link">Cancel</button>
154      <p class="help-block" id="hintError-sstate_dir" style="display:none;">The directory path cannot include spaces or any of these characters: \ ? % * : | " " &lt; &gt;</p>
155      <p class="help-block" id="hintError-initialChar-sstate_dir" style="display:none;">The directory path should either start with a /, e.g. /home/toaster/sstate-cache; or with a variable, e.g. ${TOPDIR}/sstate-cache.</p>
156    </form>
157    </dd>
158    {% endif %}
159  </dl>
160
161  <!-- <ul class="list-unstyled configuration-list" id="configvar-list"> -->
162  <dl id="configvar-list">
163    <!-- the added configuration variables are inserted here -->
164  </dl>
165
166  <!-- pass the fstypes list, black list, and externally managed variables here -->
167  {% for fstype in vars_fstypes %}
168  <input type="hidden" class="js-checkbox-fstypes-list" value="{{fstype}}">
169  {% endfor %}
170  {% for b in vars_disallowed %}
171  <input type="hidden" class="js-config-disallowed-name" value="{{b}}">
172  {% endfor %}
173  {% for b in vars_managed %}
174  <input type="hidden" class="js-config-managed-name" value="{{b}}">
175  {% endfor %}
176
177  <form id="variable-form">
178    <fieldset>
179      <legend>Add variable</legend>
180      <div class="row">
181        <div class="col-md-3">
182          <div id="add-configvar-name-div" class="form-group">
183            <label class="control-label">
184              Variable
185              <span class="glyphicon glyphicon-question-sign get-help"
186                    title="Variable names are case sensitive,
187                    cannot have spaces, and can only include letters, numbers, underscores
188                    and dashes"></span>
189            </label>
190            <input type="text" class="form-control" placeholder="Type the variable name" id="variable">
191          </div>
192          <p class="help-block" id="new-variable-error-message"></p>
193          <div class="form-group">
194            <label clas="control-label">Value</label>
195            <input id="value" type="text" class="form-control" placeholder="Type the variable value">
196          </div>
197          <button id="add-configvar-button" class="btn btn-default save" type="button" disabled>Add variable</button>
198        </div>
199        <div class="col-md-5 help-block">
200          <h5>Some variables cannot be set from Toaster</h5>
201          <p>Toaster cannot set any variables that impact 1) the configuration of the build servers,
202          or 2) where artifacts produced by the build are stored. Such variables include: </p>
203          <p>
204          <code><a href="http://docs.yoctoproject.org/ref-manual/variables.html#term-BB_DISKMON_DIRS" target="_blank">BB_DISKMON_DIRS</a></code>
205          <code><a href="http://docs.yoctoproject.org/ref-manual/variables.html#term-BB_NUMBER_THREADS" target="_blank">BB_NUMBER_THREADS</a></code>
206          <code>CVS_PROXY_HOST</code>
207          <code>CVS_PROXY_PORT</code>
208          <code><a href="http://docs.yoctoproject.org/ref-manual/variables.html#term-PARALLEL_MAKE" target="_blank">PARALLEL_MAKE</a></code>
209          <code><a href="http://docs.yoctoproject.org/ref-manual/variables.html#term-TMPDIR" target="_blank">TMPDIR</a></code></p>
210          <p>Plus the following standard shell environment variables:</p>
211          <p><code>http_proxy</code> <code>ftp_proxy</code> <code>https_proxy</code> <code>all_proxy</code></p>
212        </div>
213      </div>
214    </fieldset>
215  </form>
216</div>
217
218</div>
219
220<script>
221
222// global variables
223var do_reload=false;
224
225// validate new variable name
226function validate_new_variable() {
227  var variable = $("input#variable").val();
228  var value    = $("input#value").val();
229
230  // presumed innocence
231  $('#new-variable-error-message').text("");
232  var error_msg = "";
233
234  var existing_configvars = document.getElementsByClassName('js-config-var-name');
235  for (var i = 0, length = existing_configvars.length; i < length; i++) {
236    if (existing_configvars[i].innerHTML.toUpperCase() == variable.toUpperCase()) {
237      error_msg = "This variable is already set in this page. Edit its value instead";
238    }
239  }
240
241  var disallowed_configvars = document.getElementsByClassName('js-config-disallowed-name');
242  for (var i = 0, length = disallowed_configvars.length; i < length; i++) {
243    if (disallowed_configvars[i].value.toUpperCase() == variable.toUpperCase()) {
244      error_msg = "You cannot edit this variable in Toaster because it is set by the build servers";
245    }
246  }
247
248  var managed_configvars = document.getElementsByClassName('js-config-managed-name');
249  for (var i = 0, length = managed_configvars.length; i < length; i++) {
250    if (managed_configvars[i].value.toUpperCase() == variable.toUpperCase()) {
251      error_msg = "You cannot set this variable here. Please set it in the <a href=\"{% url 'project' project.id %}\">project main page</a>";
252    }
253  }
254
255  var bad_chars  = /[^a-zA-Z0-9\-_/]/.test(variable);
256  var has_spaces = (0 <= variable.indexOf(" "));
257  var only_spaces = (0 < variable.length) && (0 == variable.trim().length);
258
259  if (only_spaces) {
260    error_msg = "A valid variable name cannot include spaces";
261  } else if (bad_chars && has_spaces) {
262    error_msg = "A valid variable name can only include letters, numbers and the special characters <code> _ - /</code>. Variable names cannot include spaces";
263  } else if (bad_chars) {
264    error_msg = "A valid variable name can only include letters, numbers and the special characters <code>_ - /</code>";
265  }
266
267  if ("" != error_msg) {
268    $('#new-variable-error-message').html(error_msg);
269    $(".save").attr("disabled","disabled");
270
271    // add one (and only one) error class append
272    $("#add-configvar-name-div").addClass("has-error");
273    $("#new-variable-error-message").addClass("text-danger");
274
275    return false;
276  } else if (0 == variable.length) {
277    $(".save").attr("disabled","disabled");
278    return false;
279  }
280
281  $("#add-configvar-name-div").removeClass("has-error");
282
283  // now set the "Save" enablement if 'value' also passes
284  if (value.trim().length > 0) {
285    $(".save").removeAttr("disabled");
286  } else {
287    $(".save").attr("disabled","disabled");
288  }
289
290  return true;
291}
292
293// validate distro name
294function validate_distro_name() {
295  var value    = $("input#new-distro").val();
296
297  // presumed innocence
298  $('#distro-error-message').text("");
299  var error_msg = "";
300
301  var has_spaces = (0 <= value.indexOf(" "));
302
303  if (has_spaces) {
304    error_msg = "A valid distro name cannot include spaces";
305  } else if (0 == value.length) {
306    error_msg = " ";
307  }
308
309  if ("" != error_msg) {
310    $('#distro-error-message').text(error_msg);
311    $("#apply-change-distro").attr("disabled","disabled");
312
313    // add one (and only one) error class append
314    $("#change-distro-form").addClass("has-error");
315
316    return false;
317  }
318
319  $("#change-distro-form").removeClass("has-error");
320  $("#apply-change-distro").removeAttr("disabled");
321  return true;
322}
323
324// Test to insure at least one FS Type is checked
325function enableFsTypesSave() {
326  var any_checked = 0;
327  $(".fs-checkbox-fstypes:checked").each(function(){
328    any_checked = 1;
329  });
330  if ( 0 == any_checked ) {
331    $("#apply-change-image_fstypes").attr("disabled","disabled");
332    $('.scrolling').addClass('has-error');
333    $('#fstypes-error-message').show();
334  }
335  else {
336    $("#apply-change-image_fstypes").removeAttr("disabled");
337    $('.scrolling').removeClass('has-error');
338    $('#fstypes-error-message').hide();
339  }
340}
341
342// Preset or reset the Package Class checkbox labels
343function updatePackageClassCheckboxes() {
344  $('#package_class_1, #package_class_2').hide();
345  if ($('select').val() == 'package_deb') {
346    $('#package_class_1').html('<input type="checkbox" id="package_class_1_input"> package_ipk');
347    $('#package_class_2').html('<input type="checkbox" id="package_class_2_input"> package_rpm');
348  }
349  if ($('select').val() == 'package_ipk') {
350    $('#package_class_1').html('<input type="checkbox" id="package_class_1_input"> package_deb');
351    $('#package_class_2').html('<input type="checkbox" id="package_class_2_input"> package_rpm');
352  }
353  if ($('select').val() == 'package_rpm') {
354    $('#package_class_1').html('<input type="checkbox" id="package_class_1_input"> package_deb');
355    $('#package_class_2').html('<input type="checkbox" id="package_class_2_input"> package_ipk');
356  }
357  $('#package_class_1, #package_class_2').fadeIn(1500);
358}
359
360// Re-assert handlers when the page is served and/or refreshed via Ajax
361function setEventHandlersForDynamicElements() {
362
363  // change variable value
364  $('.js-icon-pencil-config_var').click(function (evt) {
365    var pk = $(this).attr("x-data");
366    var current_val = $("#config_var_value_"+pk).text();
367    $("#config_var_value_"+pk).hide();
368    $("#config_var_trash_"+pk).hide();
369    $(".js-icon-pencil-config_var[x-data="+pk+"]").hide();
370    $("#change-config_var-form_"+pk).slideDown();
371    $("#new-config_var_"+pk).val(current_val);
372    if ( $("#new-config_var_"+pk).val().length ) {
373      $("#apply-change-config_var_"+pk).removeAttr("disabled");
374    }
375    else {
376      $("#apply-change-config_var_"+pk).attr("disabled");
377    }
378  });
379
380  $('.js-cancel-change-config_var').click(function (evt) {
381    var pk = evt.target.attributes["x-data"].value;
382    $("#change-config_var-form_"+pk).slideUp(function() {
383      $("#config_var_trash_"+pk).show();
384      $('#config_var_value_'+pk).show();
385      $(".js-icon-pencil-config_var[x-data="+pk+"]").show();
386    });
387  });
388
389  $(".js-new-config_var").on('input', function(){
390    if ($(this).val().length == 0) {
391      $(this).parent("div").next(".btn-default").attr("disabled","disabled");
392    }
393    else {
394      $(this).parent("div").next(".btn-default").removeAttr("disabled");
395    }
396  });
397
398  $('.js-apply-change-config_var').click(function (evt) {
399    var xdata    = evt.target.attributes["x-data"].value.split(":");
400    var pk       = xdata[0];
401    var variable = xdata[1];
402    var val      = $('#new-config_var_'+pk).val();
403    postEditAjaxRequest({"configvarChange" : variable+':'+val});
404    $("#change-config_var-form_"+pk).slideUp();
405    $("#config_var_trash_"+pk).fadeIn();
406    $('#config_var_value_'+pk).fadeIn();
407    $(".js-icon-pencil-config_var[x-data="+pk+"]").fadeIn();
408  });
409
410  // delete variable
411  $(".js-icon-trash-config_var").click(function (evt) {
412    var pk = $(this).attr("x-data");
413
414    // fade out the variable+value div, then refresh the variable list
415    $(this).fadeOut();
416    $(this).tooltip("hide");
417    $("config_var_entry_"+pk).fadeOut();
418    $('#config_var_value_'+pk).parent("dd").fadeOut();
419    postEditAjaxRequest({"configvarDel": evt.target.attributes["x-data"].value});
420  });
421
422}
423
424function onEditPageUpdate(data) {
425  // update targets
426  var i; var orightml = "";
427
428  var configvars_sorted = data.configvars.sort(function(a, b){return a[0] > b[0]});
429
430  var managed_configvars = document.getElementsByClassName('js-config-var-managed-name');
431
432  for (i = 0; i < configvars_sorted.length; i++) {
433    // skip if the variable name has a special context (not user defined)
434    var var_context=undefined;
435    for (var j = 0, length = managed_configvars.length; j < length; j++) {
436      if ((managed_configvars[j].innerHTML == configvars_sorted[i][0]) ||
437          (managed_configvars[j].value     == configvars_sorted[i][0]) ) {
438        var_context='m';
439      }
440    }
441    if (configvars_sorted[i][0].startsWith("INTERNAL_")) {
442        var_context='m';
443    }
444    if (var_context == undefined) {
445        orightml += '<dt><span id="config_var_entry_'+configvars_sorted[i][2]+'" class="js-config-var-name"></span><span class="glyphicon glyphicon-trash js-icon-trash-config_var" id="config_var_trash_'+configvars_sorted[i][2]+'" x-data="'+configvars_sorted[i][2]+'"></span> </dt>'
446        orightml += '<dd class="variable-list">'
447        orightml += '    <span class="lead" id="config_var_value_'+configvars_sorted[i][2]+'"></span>'
448        orightml += '    <span class="glyphicon glyphicon-edit js-icon-pencil-config_var" x-data="'+configvars_sorted[i][2]+'"></span>'
449        orightml += '    <form class="form-inline" id="change-config_var-form_'+configvars_sorted[i][2]+'" style="display:none;">'
450        orightml += '        <div class="form-group">'
451        orightml += '            <input type="text" class="form-control js-new-config_var" id="new-config_var_'+configvars_sorted[i][2]+'" value=""></div>'
452        orightml += '            <button id="apply-change-config_var_'+configvars_sorted[i][2]+'" class="btn btn-default js-apply-change-config_var" type="button" x-data="'+configvars_sorted[i][2]+':'+configvars_sorted[i][0]+'" disabled>Save</button>'
453        orightml += '            <button type="button" class="btn btn-link js-cancel-change-config_var" x-data="'+configvars_sorted[i][2]+'">Cancel</button>'
454        orightml += '    </form>'
455        orightml += '</dd>'
456    }
457  }
458
459  // update configvars list HTML framework
460  $("dl#configvar-list").html(orightml);
461
462  // insert the name/value pairs safely as non-HTML
463  for (i = 0; i < configvars_sorted.length; i++) {
464    $('#config_var_entry_'+configvars_sorted[i][2]).text(configvars_sorted[i][0]);
465    $('#config_var_value_'+configvars_sorted[i][2]).text(configvars_sorted[i][1]);
466  }
467
468  // Add the tooltips
469  $(".js-icon-trash-config_var").each( function(){ setDeleteTooltip($(this)); });
470  $(".js-icon-pencil-config_var").each(function(){ setChangeTooltip($(this)); });
471
472  // re-assert these event handlers
473  setEventHandlersForDynamicElements();
474}
475
476function onEditAjaxSuccess(data, textstatus) {
477  console.log("XHR returned:", data, "(" + textstatus + ")");
478  if (data.error != "ok") {
479    alert("error on request:\n" + data.error);
480    return;
481  }
482
483  // delayed page reload?
484  if (do_reload) {
485    do_reload=false;
486    location.reload(true);
487  } else {
488    onEditPageUpdate(data);
489  }
490}
491
492function onEditAjaxError(jqXHR, textstatus, error) {
493  alert("XHR errored:\n" + error + "\n(" + textstatus + ")");
494  // re-assert the event handlers
495}
496
497/* ensure cookie exists {% csrf_token %} */
498function postEditAjaxRequest(reqdata) {
499  var ajax = $.ajax({
500    type:"POST",
501    data: $.param(reqdata),
502    url:"{% url 'xhr_configvaredit' project.id%}",
503    headers: { 'X-CSRFToken': $.cookie("csrftoken")},
504    success: onEditAjaxSuccess,
505    error: onEditAjaxError,
506  })
507}
508
509function setDeleteTooltip(object) {
510  object.tooltip({ container: 'body', html: true, delay: {show: 400}, title: "Delete" });
511}
512function setChangeTooltip(object) {
513  object.tooltip({ container: 'body', html: true, delay: {show: 400}, title: "Change" });
514}
515
516$(document).ready(function() {
517
518  //
519  // Register handlers for static elements
520  //
521
522  {% if distro_defined %}
523  // change distro variable
524  $('#change-distro-icon').click(function() {
525    $('#change-distro-icon, #distro').hide();
526    $("#change-distro-form").slideDown();
527    $("#new-distro").val( $('#distro').text() );
528    $("#apply-change-distro").removeAttr("disabled");
529  });
530
531  $('#cancel-change-distro').click(function(){
532    $("#change-distro-form").slideUp(function() {
533      $('#distro, #change-distro-icon').show();
534
535      // reset any dangling error state
536      $('#distro-error-message').text("");
537      $("#change-distro-form").removeClass("has-error");
538    });
539  });
540
541  // validate new distro name
542  $("input#new-distro").on('input', function (evt) {
543    validate_distro_name();
544  });
545
546  $('#apply-change-distro').click(function(){
547    //$('#repo').parent().removeClass('highlight-go');
548    var name = $('#new-distro').val();
549    postEditAjaxRequest({"configvarChange" : 'DISTRO:'+name});
550    $('#distro').text(name);
551    $("#change-distro-form").slideUp(function () {
552      $('#distro, #change-distro-icon').show();
553    });
554  });
555  {% endif %}
556
557  {% if dl_dir_defined %}
558
559  // change DL_DIR variable
560  $('#change-dl_dir-icon').click(function() {
561    $('#change-dl_dir-form').removeClass('has-error');
562    // preset the edit value
563    var current_val = $("#dl_dir").text().trim();
564    if (current_val == "Not set") {
565      current_val="";
566      $("#apply-change-dl_dir").attr("disabled","disabled");
567    }
568    $("input#new-dl_dir").val(current_val);
569    // enable / disable the save button based on the input value
570    if ( current_val.length ) {
571      $("#apply-change-dl_dir").removeAttr("disabled");
572    }
573    else {
574      $("#apply-change-dl_dir").attr("disabled","disabled");
575    }
576
577    $('#change-dl_dir-icon, #dl_dir').hide();
578    $("#change-dl_dir-form").slideDown();
579  });
580
581  $('#cancel-change-dl_dir').click(function(){
582    $("#hintError-dl_dir").hide();
583    $("#hintError-initialChar-dl_dir").hide();
584    $("#change-dl_dir-form").slideUp(function() {
585      $('#dl_dir, #change-dl_dir-icon').show();
586    });
587  });
588
589  $("#new-dl_dir").on('input', function(){
590    if ($(this).val().trim().length == 0) {
591      $("#apply-change-dl_dir").attr("disabled","disabled");
592      $('#change-dl_dir-form').addClass('has-error');
593      $('#hintError-dl_dir').hide();
594      $('#hintError-initialChar-dl_dir').hide();
595    }
596    else {
597      var input = $(this);
598      var reBeginWithSlash = /^\//;
599      var reCheckVariable = /^\$/;
600      var re = /([ <>\\|":%\?\*]+)/;
601      var invalidDir = re.test(input.val());
602      var invalidSlash = reBeginWithSlash.test(input.val());
603      var invalidVar = reCheckVariable.test(input.val());
604      if (!invalidSlash && !invalidVar) {
605        $('#change-dl_dir-form').addClass('has-error');
606        $("#apply-change-dl_dir").attr("disabled","disabled");
607        $('#hintError-initialChar-dl_dir').show();
608      } else if (invalidDir) {
609        $('#change-dl_dir-form').addClass('has-error');
610        $("#apply-change-dl_dir").attr("disabled","disabled");
611        $('#hintError-dl_dir').show();
612      } else {
613        $('#change-dl_dir-form').removeClass('has-error');
614        $("#apply-change-dl_dir").removeAttr("disabled");
615        $('#hintError-dl_dir').hide();
616        $('#hintError-initialChar-dl_dir').hide();
617      }
618    }
619  });
620
621  $('#apply-change-dl_dir').click(function(){
622    var value = $('#new-dl_dir').val().trim();
623    postEditAjaxRequest({"configvarChange" : 'DL_DIR:'+value});
624    $('#dl_dir').text(value);
625    $('#dl_dir').removeClass('muted');
626    $("#change-dl_dir-form").slideUp(function () {
627      $('#dl_dir, #change-dl_dir-icon').show();
628    });
629  });
630
631  {% endif %}
632
633  {% if fstypes_defined %}
634  // change IMAGE_FSTYPES variable
635
636  // get value of fstypes and add to the textbox
637  $("#new-imagefs_types").val("{{fstypes}}");
638
639  // If value of new-imagefs_types is empty disable save button
640  $("#new-imagefs_types").on("input", function() {
641    $(this).val($(this).val().replace(/\s+/g,' '));
642    if ($(this).val().length === 0) {
643      //$('#apply-change-image_fstypes').prop('disabled', true);
644      $('#apply-change-image_fstypes').attr("disabled", "disabled");
645    } else {
646      //$('#apply-change-image_fstypes').prop('disabled', false);
647      $('#apply-change-image_fstypes').removeAttr("disabled");
648    }
649
650    /*If user types imagefs do the action on checkboxes.
651      Lets say if an imagefstype typed by user and the same
652      imagefs is unchecked in the checkbox, then checkbox needs
653      to get checked. Similarly when user deletes imagefs from
654      textbox the checkbox which is checked gets unchecked.
655     */
656    $('#all-image_fstypes input').each(function(){
657      var imagefs_userval = $('#new-imagefs_types').val();
658      if( imagefs_userval.indexOf($(this).val()) > -1) {
659        $(this).prop('checked', true);
660      } else {
661        $(this).prop('checked', false);
662      }
663    });
664
665    // Validate underscore in image fs types
666    if ($(this).val().indexOf('_') > -1) {
667      $('#validate-image_fstypes').addClass('has-error');
668      $('#hintError-image-fs_type').show();
669      $("#apply-change-image_fstypes").prop("disabled", true);
670    } else {
671      $('#validate-image_fstypes').removeClass('has-error');
672      $('#hintError-image-fs_type').hide();
673    }
674  });
675
676  $('#change-image_fstypes-icon').click(function() {
677    $('#change-image_fstypes-icon, #image_fstypes').hide();
678    $("#change-image_fstypes-form").slideDown();
679    // avoid false substring matches by including space separators
680    var html         = "";
681    var fstypes      = " " + document.getElementById("image_fstypes").innerHTML + " ";
682    var fstypes_list = document.getElementsByClassName('js-checkbox-fstypes-list');
683    // Add the checked boxes first
684    if ("  " != fstypes) {
685      for (var i = 0, length = fstypes_list.length; i < length; i++) {
686        if (0 <= fstypes.indexOf(" "+fstypes_list[i].value+" ")) {
687          html += '<div class="checkbox"><label><input type="checkbox" class="fs-checkbox-fstypes" value="'+fstypes_list[i].value+'" checked="checked">'+fstypes_list[i].value+'</label></div>';
688        }
689      }
690    }
691    // Add the un-checked boxes second
692    for (var i = 0, length = fstypes_list.length; i < length; i++) {
693      if (0  > fstypes.indexOf(" "+fstypes_list[i].value+" ")) {
694        html += '<div class="checkbox"><label><input type="checkbox" class="fs-checkbox-fstypes" value="'+fstypes_list[i].value+'">'+fstypes_list[i].value+'</label></div>';
695      }
696    }
697    // Add the 'no search matches' line last
698    html += '<label id="no-match-fstypes" class="text-muted">No image types found</label>\n';
699    // Display the list
700    document.getElementById("all-image_fstypes").innerHTML = html;
701    $('#no-match-fstypes').hide();
702
703    // clear the previous filter values and warning messages
704    $("input#filter-image_fstypes").val("");
705  });
706
707  // When checkbox is checked/unchecked kindly update the text
708  $(document).on("change", "#all-image_fstypes :checkbox", function() {
709    var imagefs = $(this);
710    var imagefs_obj = $('#new-imagefs_types');
711    var imagefs_userval = imagefs_obj.val();
712    if ($(this).is(':checked')) {
713      if (imagefs_userval.indexOf($(imagefs).val()) === -1) {
714        imagefs_obj.val(imagefs_userval + " " + $(imagefs).val());
715      }
716    } else {
717      if (imagefs_userval.indexOf($(imagefs).val()) > -1) {
718        imagefs_obj.val(imagefs_userval.replace($(imagefs).val(), '').trim());
719      }
720    }
721    if ($('#new-imagefs_types').val().length === 0) {
722      $("#apply-change-image_fstypes").prop("disabled", true);
723      $('#fstypes-error-message').show();
724    } else {
725      $("#apply-change-image_fstypes").prop("disabled", false);
726      $('#fstypes-error-message').hide();
727    }
728  });
729
730  $('#cancel-change-image_fstypes').click(function(){
731    $("#new-imagefs_types").val("{{fstypes}}");
732    $("#change-image_fstypes-form").slideUp(function() {
733      $('#image_fstypes, #change-image_fstypes-icon').show();
734    });
735  });
736
737  $('#filter-image_fstypes').on('input', function(){
738    var valThis = $(this).val().toLowerCase();
739    var matchCount=0;
740    $('#all-image_fstypes label').each(function(){
741      var text = $(this).text().toLowerCase();
742      var match = text.indexOf(valThis);
743      if (match >= 0) {
744        $(this).show();
745        matchCount += 1;
746      }
747      else {
748        $(this).hide();
749      }
750    });
751    if (matchCount === 0) {
752      $('#no-match-fstypes').show();
753    } else {
754      $('#no-match-fstypes').hide();
755    }
756  });
757
758  $('#apply-change-image_fstypes').click(function(){
759    var fstypes = $('#new-imagefs_types').val();
760
761    postEditAjaxRequest({"configvarChange" : 'IMAGE_FSTYPES:'+fstypes});
762    $('#image_fstypes').text(fstypes);
763    $('#image_fstypes').parent().removeClass('muted');
764
765    $("#change-image_fstypes-form").slideUp(function() {
766      $('#image_fstypes, #change-image_fstypes-icon').show();
767    });
768  });
769  {% endif %}
770
771
772  {% if image_install_append_defined %}
773
774  // init IMAGE_INSTALL:append trash icon
775  setDeleteTooltip($('#delete-image_install-icon'));
776
777  // change IMAGE_INSTALL:append variable
778  $('#change-image_install-icon').click(function() {
779    // preset the edit value
780    var current_val = $("span#image_install").text().trim();
781    if (current_val == "Not set") {
782      current_val="";
783      $("#apply-change-image_install").attr("disabled","disabled");
784    } else {
785      // insure these non-empty values have single space prefix
786      current_val=" " + current_val;
787      $("#apply-change-image_install").removeAttr("disabled");
788    }
789    $("input#new-image_install").val(current_val);
790
791    $('#change-image_install-icon, #delete-image_install-icon, #image_install').hide();
792    $("#change-image_install-form").slideDown();
793  });
794
795  $('#cancel-change-image_install').click(function(){
796    $("#change-image_install-form").slideUp(function() {
797      $('#image_install, #change-image_install-icon').show();
798      if ($("span#image_install").text() != "Not set") {
799        $('#delete-image_install-icon').show();
800        setDeleteTooltip($('#delete-image_install-icon'));
801      }
802    });
803  });
804
805  $("#new-image_install").on('input', function(){
806    if ($(this).val().trim().length == 0) {
807      $("#apply-change-image_install").attr("disabled","disabled");
808    }
809    else {
810      $("#apply-change-image_install").removeAttr("disabled");
811    }
812  });
813
814  $('#apply-change-image_install').click(function(){
815    // insure these non-empty values have single space prefix
816    var value = " " + $('#new-image_install').val().trim();
817    postEditAjaxRequest({"configvarChange" : 'IMAGE_INSTALL:append:'+value});
818    $('#image_install').text(value);
819    $('#image_install').removeClass('text-muted');
820    $("#change-image_install-form").slideUp(function () {
821      $('#image_install, #change-image_install-icon').show();
822      if (value.length > -1) {
823        $('#delete-image_install-icon').show();
824        setDeleteTooltip($('#delete-image_install-icon'));
825      }
826    });
827  });
828
829  // delete IMAGE_INSTALL:append variable value
830  $('#delete-image_install-icon').click(function(){
831    $(this).tooltip('hide');
832    postEditAjaxRequest({"configvarChange" : 'IMAGE_INSTALL:append:'+''});
833    $('#image_install').parent().fadeOut(1000, function(){
834      $('#image_install').addClass('text-muted');
835      $('#image_install').text('Not set');
836      $('#delete-image_install-icon').hide();
837      $('#image_install').parent().fadeIn(1000);
838    });
839  });
840  {% endif %}
841
842
843  {% if package_classes_defined %}
844  // change PACKAGE_CLASSES variable
845  $('#change-package_classes-icon').click(function() {
846    $('#change-package_classes-icon, #package_classes').hide();
847    $("#change-package_classes-form").slideDown();
848
849    // initialize the pulldown and checkboxes
850    var value = $("#package_classes").text();
851    if ( value.indexOf("package_deb") == 0 ) {
852      $("#package_classes-select").prop('selectedIndex', 0);
853      updatePackageClassCheckboxes();
854      if ( value.indexOf("_ipk") > 0 ) {
855        $("#package_class_1_input").attr("checked",true);
856      }
857      if ( value.indexOf("_rpm") > 0 ) {
858        $("#package_class_2_input").attr("checked",true);
859      }
860    }
861
862    if ( value.indexOf("package_ipk") == 0 ) {
863      $("#package_classes-select").prop('selectedIndex', 1);
864      updatePackageClassCheckboxes();
865      if ( value.indexOf("_deb") > 0 ) {
866        $("#package_class_1_input").attr("checked",true);
867      }
868      if ( value.indexOf("_rpm") > 0 ) {
869        $("#package_class_2_input").attr("checked",true);
870      }
871    }
872
873    if ( value.indexOf("package_rpm") == 0 ) {
874      $("#package_classes-select").prop('selectedIndex', 2);
875      updatePackageClassCheckboxes();
876      if ( value.indexOf("_deb") > 0 ) {
877        $("#package_class_1_input").attr("checked",true);
878      }
879      if ( value.indexOf("_ipk") > 0 ) {
880        $("#package_class_2_input").attr("checked",true);
881      }
882    }
883  });
884
885  $('#cancel-change-package_classes').click(function(){
886    $("#change-package_classes-form").slideUp(function() {
887      $('#package_classes, #change-package_classes-icon').show();
888    });
889  });
890
891  $('select').change(function() {
892    updatePackageClassCheckboxes();
893  });
894
895  $('#apply-change-package_classes').click(function(){
896    var e   = document.getElementById("package_classes-select");
897    var val = e.options[e.selectedIndex].text;
898
899    pc1_checked = document.getElementById("package_class_1_input").checked;
900    pc2_checked = document.getElementById("package_class_2_input").checked;
901    if (val == "package_deb") {
902      if (pc1_checked) val = val + " package_ipk";
903      if (pc2_checked) val = val + " package_rpm";
904    }
905    if (val == "package_ipk") {
906      if (pc1_checked) val = val + " package_deb";
907      if (pc2_checked) val = val + " package_rpm";
908    }
909    if (val == "package_rpm") {
910      if (pc1_checked) val = val + " package_deb";
911      if (pc2_checked) val = val + " package_ipk";
912    }
913
914    $('#package_classes').text(val);
915    //$('#package_classes').parent().removeClass('muted');
916    postEditAjaxRequest({"configvarChange" : 'PACKAGE_CLASSES:'+val});
917    $("#change-package_classes-form").slideUp(function() {
918      $('#package_classes, #change-package_classes-icon').show();
919    });
920  });
921  {% endif %}
922
923  {% if sstate_dir_defined %}
924
925  // change SSTATE_DIR variable
926  $('#change-sstate_dir-icon').click(function() {
927    $('#change-sstate_dir-form').removeClass('has-error');
928    // preset the edit value
929    var current_val = $("span#sstate_dir").text().trim();
930    if (current_val == "Not set") {
931      current_val="";
932      $("#apply-change-sstate_dir").attr("disabled","disabled");
933    }
934    $("input#new-sstate_dir").val(current_val);
935
936    // enable / disable the save button based on the input value
937    if ( current_val.length ) {
938      $("#apply-change-sstate_dir").removeAttr("disabled");
939    }
940    else {
941      $("#apply-change-sstate_dir").attr("disabled","disabled");
942    }
943
944    $('#change-sstate_dir-icon, #sstate_dir').hide();
945    $("#change-sstate_dir-form").slideDown();
946  });
947
948  $('#cancel-change-sstate_dir').click(function(){
949    $("#hintError-sstate_dir").hide();
950    $("#hintError-initialChar-sstate_dir").hide();
951    $("#change-sstate_dir-form").slideUp(function() {
952      $('#sstate_dir, #change-sstate_dir-icon').show();
953    });
954  });
955
956  $("#new-sstate_dir").on('input', function(){
957    if ($(this).val().trim().length == 0) {
958      $("#apply-change-sstate_dir").attr("disabled","disabled");
959      $('#change-sstate_dir-form').addClass('has-error');
960      $('#hintError-sstate_dir').hide();
961      $('#hintError-initialChar-sstate_dir').hide();
962    }
963    else {
964      var input = $(this);
965      var reBeginWithSlash = /^\//;
966      var reCheckVariable = /^\$/;
967      var re = /([ <>\\|":%\?\*]+)/;
968      var invalidDir = re.test(input.val());
969      var invalidSlash = reBeginWithSlash.test(input.val());
970      var invalidVar = reCheckVariable.test(input.val());
971      if (!invalidSlash && !invalidVar) {
972        $('#change-sstate_dir-form').addClass('has-error');
973        $("#apply-change-sstate_dir").attr("disabled","disabled");
974        $('#hintError-initialChar-sstate_dir').show();
975      } else if (invalidDir) {
976          $('#change-sstate_dir-form').addClass('has-error');
977          $("#apply-change-sstate_dir").attr("disabled","disabled");
978          $('#hintError-sstate_dir').show();
979      } else {
980        $('#change-sstate_dir-form').removeClass('has-error');
981        $("#apply-change-sstate_dir").removeAttr("disabled");
982        $('#hintError-sstate_dir').hide();
983        $('#hintError-initialChar-sstate_dir').hide();
984      }
985    }
986  });
987
988  $('#apply-change-sstate_dir').click(function(){
989    var value = $('#new-sstate_dir').val().trim();
990    postEditAjaxRequest({"configvarChange" : 'SSTATE_DIR:'+value});
991    $('#sstate_dir').text(value);
992    $('#sstate_dir').removeClass('text-muted');
993    $("#change-sstate_dir-form").slideUp(function () {
994      $('#sstate_dir, #change-sstate_dir-icon').show();
995    });
996  });
997
998  {% endif %}
999
1000  // add new variable
1001  $("button#add-configvar-button").click( function (evt) {
1002    var variable = $("input#variable").val();
1003    var value    = $("input#value").val();
1004
1005    postEditAjaxRequest({"configvarAdd" : variable+':'+value});
1006
1007    // clear the previous values
1008    $("input#variable").val("");
1009    $("input#value").val("");
1010    // Disable add button
1011    $(".save").attr("disabled","disabled");
1012
1013    // Reload page if admin-removed core managed value is manually added back in
1014    if (0 <= " DISTRO DL_DIR IMAGE_FSTYPES IMAGE_INSTALL:append PACKAGE_CLASSES SSTATE_DIR ".indexOf( " "+variable+" " )) {
1015      // delayed reload to avoid race condition with postEditAjaxRequest
1016      do_reload=true;
1017    }
1018  });
1019
1020  // validate new variable name and value
1021  $("#variable, #value").on('input', function() {
1022    validate_new_variable();
1023  });
1024
1025  //
1026  // draw and register the dynamic configuration variables and handlers
1027  //
1028
1029  var data = {
1030    configvars : []
1031  };
1032  {% for c in configvars %}
1033  data.configvars.push([ "{{c.name}}","{{c.value}}","{{c.pk}}" ]);
1034  {% if '' != vars_context|get_dict_value:c.name %}
1035  data.vars_context[ "{{c.name}}" ] = "{{vars_context|get_dict_value:c.name }}";
1036  {% endif %}
1037  {% endfor %}
1038
1039  // draw these elements and assert their event handlers
1040  onEditPageUpdate(data);
1041});
1042
1043</script>
1044
1045{% endblock %}
1046